[Zope-DB] Re: [Psycopg] Transactions with Zope

Hannu Krosing hannu@tm.ee
Fri, 25 Jan 2002 18:51:40 +0200


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

"Matthew T. Kromer" wrote:
> 
> On Friday, January 25, 2002, at 04:09 AM, Hannu Krosing wrote:
> >
> > It is a hairy problem deep in Zope transaction management that manifests
> > itself when something raises an exception during commit and then the
> > finally: clause clears a list of registrees before abort is called.
> >
> 
> When you come back in, I'd like to hear more about this; if there is
> something broken with either the transaction manager semantics OR how
> the DA is registering itself with the transaction manager I may be able
> to help.

I'm not sure about the tm semantics but you can try this test case which
will leave a bunch of uncommitted transactions.

We are not completely sure what goes wrong but we can make it _not_ go
wrong by changing Transaction.py to attached version (added 
_commit_succeeded lines)

It seems that if an error is raised during first commit pass, then
somehow 
self._registered of the DA stays 1 and all subsequent registration
attempts 
will fail (as it seems to be already registered with transaction
manager) 
and thus neither commit nor abort will never be called.

BTW, is there some nice writeup of Zope transaction management ?

-------------
Hannu
--------------B3E3FDC4940D6BD680EDC7F6
Content-Type: application/x-gzip;
 name="trxtest.tar.gz"
Content-Transfer-Encoding: base64
Content-Disposition: inline;
 filename="trxtest.tar.gz"

H4sIAA2JUTwAA+yaeXRURdbAk5BA0pBAANmRZ1jSYOgshAAhCXZIICAEJHkIkdi8dFfSTbr7
9Vs6IUjEZQRHBXEDBUURviDuijoKn8vMCLKJG5sCAbIou2wDCDhOVd370kkIOn98Ouc7Z/qc
pH/ddW/VrVu37q3X703JtmZNzLbkT8sP+t1eCYkJCSkpyUEJ9DUsZWiTd/YamjIsKGFYclLy
kITkxCFJVD4xOTk5SEj4/UwKvPyaLqmCEOSUvF7/r8j9Vvv/05cpPzsvX8jLzhcnm0yDBL9G
BJ9WYZd9JUKW1WTySKVEECSvQyAen14hOCRdKpKokE403WSichUcLexdFrJn68SruWSvZjK5
PD5Z1aF1DpntY+1zZB8RzOWgThxCAfucZEm2DBloMulOlyaUu9xuQZM9RHd5iCa4iVRGBLvs
9RK7TvsVXF4hlv7pquTVJP5VrEBXUCcmgXcaT2WL3S67bitWJdoD0Rt3LLk9sqbTt3KpQhPs
Eptus+4EV7FQIfuFcsmrM5OLiKD5VRJncnntKuFTdxLB6/cUEVWQiwUYxhjd43KWEretUX9a
SxaZ/tPL3vDCxftdx/it/Z+SmGLs/8TElCF8/w8Z8t/9/0e8YmJiTDR4c/x+pzOOxjDxEKGs
zlVK47yUx22p7hI8hOiyw2UycWnc2Fa74ndpLhbjDXud7lmTyUGKBbZVdDIaI9+sEXfxwFQ6
Dn0xFtIbq1skxcaSCoiZQIxuQ6+sC05Jk3Rd5U1xQmyxLCfGGj0ZvVnYt7TLuypNpqZf3sEs
srB/5oGFVKLRx4Z5yBq3uIToNl+JzafKdjvRNKKZcRi7x0E1Y32aMJjIvIc4u+zxsJw4VyhR
iU/w0ZxCQTM+Dy7j77FgDUuZtANZs/hotvOaaX8DLdQ9DmoDa1eJ7le9XOw/kBYa0vPvOMav
73+6+1MSYf8nDUuhf1Q+KYGmhP/u/z/gVZA9bTJQp83w3v1Ts1k0TRqTZxkjux1EVYLF1kgh
utIqV7dUKqFmMZTtLyWsUmltHmvdcdOaqCOTOiLk5nBok3a2AOHMYwzW/nxs6XiEJZ0B3tl6
A8KWQQyq6taknzMgiTddvW1DEcL6coD0rakIW1I4HNzc/WmEbs9yuPLk8AiEYRYA+xwbQsVA
gJTasQg1Izlc3nBgCML+WA47hBHTEIYTDj9ND12O0Op5gJTY8QgDxnC4dGF/X4R9wzlcPF3Z
FuGudQDzR65CSF3K4cLVn2MQrkYCbFi8BeHRjQCeS2sRLr4HEBOKMjGtXuWwK7xwIcIMGOL8
prtuR6iwgXuXPHjJgGHQVPzA0wh/+ojDOfmdDQjrvgToO+KcAeEcznoSfkKI/xmg/yKCsHAO
hzNHq59EOLAYYN22iwhbrwBMf+E5hOdhgmeiyZ0IjrkcTl9oHY4Q+hWHugXdNyF02wpNXZdV
ITzzMg+/kLdgvSi0Aq0fX1p2AOGZzQBj7rYiVOYC9P+4D8JHyRxOzd8ShPDZcVi45f10hL6D
OZzcuSACYX4XcO+ywzkIh+6GptBR/REyIA5PbEmYjhB/JwivHjgXwcyXoKr2xsxPEKy/gHDb
V5cjvMLjsKq+Iu0dhJHg1eODym9HKJvB4diZb+IQvhYACh69G2GRC4aI+MCM8P5U3nT01XtD
EOb9kzfVJE5vhzBtNDSZLndB+AmC/8jKIV6EJAngjqAPAQp++SuHHz55rwrhXQi2H57t/Z0B
4PCtBf4fEXTw/A/dZq1HcO3h8P2RBzoi3A9x+P0b5vEIseCE77P2bkPYsxegTylq9ZkVxaF+
y8i/IqR+Ds68z78KAUevd4x7BiHndZjyzUl3ISQuALcMbhWOEDIWlvIvr9yK8PJ94N4j5BEE
Bzes6lDRpCyE3Puh6aBVR7gF9nLt66vnIax6BCBnyb0IT60A4chzuIKRZ0t4U82JUZ0RMOpq
PPXHEeqqAQYE+QH6/6JwOLzssXCExb15h4cdbXshmKbwpkMbd5ci7JoNxt8/6V2E3PMAc7vW
GgAOP/jPofEIyTzlVh18aGRvhNR8ANL7Q4ReYOrBvvfsR5h3hjdVP7V8KsKyhQCzX/rOgGgu
XB35ZB7CEzN504Hsb59B2PsZQOr92Qj3aVx4f01xJwTSFeCev583IBig05C/ISSpHPad7PU1
Qs+DAJ3KuyGU8Qmu/U67etWAHhy++Gn8gwjjYE0/X5JjRhgLhlU/s8GMsB6yRHXlxSMGQLXa
+/7ShQhLHgcYdCwV4WgGhz2enw8iXAXj9yTjTPckE0h6u3c8nYuwFFy3+9XTIxB+TAdwPbsQ
YfmLHHadWudDeLsS3PJ2n0EIN46CpsF3HUaYc4HDTincgDZnAVJT7kYY+gSEcdis2xBccAb4
5i2pF8LMRICSPScN6Mnh69p7+yDcA0nv6zf2n0bY9w+A7hOHI0zgW2/tV5/tuRNh958APqwc
jzAXJrj38LOXDWjPYE3UGW0kggpV78vcN5wIr8+H0Epp9yVC23pY7lNrTiNUQWh90f6m7xEE
yOE7Fh9JQvgBCseOaXkxCFOgdu8YdOUEwmXo8PMXVuxEeA5q9+eVq1YivPgah+3H/4cgrH4Y
QrRN7DqEAVAZt8dJBsw8xY2vV9pPQYiCoN1222QvwiTYBdu6zpuLcPefOWydN74nwjgI7N3+
MS8jZH8MScbd6W2Ejh9BYC8KeR4hGHLUlg5pAxFG9oeQ6Nqu3gAIic2jEg4hxEO62PRJdSHC
AV5qq2pye0cj9JoMprYbVI8wEHJL7Z70LQZAGqztM2IkwnAJmo4XjUeQ+Nmv6nBF5WUDYKbH
vrgzEaEQbD7s7E0Qeq0GsB0KQzgIcVhft38Iwr5beGiFvBO+BKHNp7ypekBRLoJ0B4dFkQnj
EOKLOTz21eEIhEMDONR9tPwowjJw3cHKPSEIu0H9RM+JsxAmlMMS3NsmE6F1BQxKeuQjdOde
XdMmOyoZIRKKwrdf9l+I0G8ZBFL79S8jfACl/+CwjisRoj+DbRVRuB1hxrccrs4+oCLsnweO
mvvE8wiPV8MSRF9dgHAFjhnHarrHIHTjJ+qqd1MzBQQrXA6c1nYeRfiGJZCYfm/t27QUYSNc
TSyb+8AJAyDzLxv0QTLC+5Ac6pa8/ibCaxthmV652AfhAqSUY5tCjiME74aA/EfrzxHCajhc
WFV8BIHAcWXxoq3tELbcBE2TX5uJ8CocKmr7jnsKIWcbLIFoT0cowsPkuvv3GhAFrrt9wU8I
80/Apq6cKSDY4NR0auXzMsIKDYJk1qyVCHD6qqr+s6gg5IMTtpwc3BMhDnbBo8nBNyAEwSb6
stWGRxDW3wMdesp2GQBTrt2uhSKo3cGZ76crCGl8rKpD5WHvI4Ty5Fm16othVw3oDvDhqV4I
JyGM650PXTKA74s1UednVyKU/y8LgE+Fv7+3DuHdjwFeDM1DaDUTQJtxFuEOGL1+kdYbQYWr
2tpa+3YDOkGT+ygeL91HYN33ZeBM92UolyC0bk2IRYjHYEtJC0cYCcJXqwqqEaYfA4d/m/kp
gpVfMqx9evRQgpAMFxpPt8nphzDWCiGx4ueXEK6ehpDwJDUAmLHZ0dqNEAYHzisfny9GOMcv
9teemavOR1DgavSc5eWlCGslcG/96KMGQGzUnu+5FKEH5kPfKEyVvgwHuK5HlzCEG/DEeO/Z
fxoA/nns4giCMPw+gDXLZYRlUJIWn1lZh/ACbLTFr5yejfDjXNgyE0YoCMMhnh+d8M5lA9oD
tFqRgPDcVJjOCfc+BALXF1dqnnsK4Vk4cNYM1YIQFLiUXpReNwehFpywcKe3B4IHriLryyzb
DIDzc50klSDMhHk9srnbaoSuf4OlfNNdhlD6Lkxwx4ZihPXwo8rDFusFhFvOgjPVB+9CWAAX
WedXP56B8Nho2OYPDN5mABYO/1uJCG9CddgW7I5EKIXrwe1be2xE6L4V3JvTdwVCzAGAUVdu
RLgsQgDM2NUeYScUu10be1cbALvg3NhduQg74UL+q7e3ZyBsgxPszs7zNyE8wJdp7dE5fzlp
AMyidv8tSxBGwV4+NO/mqQiD4PqidsCkMoRc8OoRfbYfoZzvizUhL9U+hFCzFYS/rslHOPwE
LO6J47sQjh0DZz7+8EiEh+BcdzTv0noE+LWn6uCcTXhNNGcjpLi61wo6IEyHKZ9OLk5DIAl+
McTlUNqIoeynXiVc7GizSXabW7ZLbpsqu4lmsykRlYpJDJMcHpdXaVuotBPDJpV7iapESprY
RdMlr0NSHTaiqrJq8xBNk0qIEmUWw/GXwx+U9mYxiv1kmJU/ccJEojtlh9JBNDX6FK3rt4nh
NrloFrHrmtLRXKl0MosRHqJLNr3CR5TOYu8CYbJx69G4zTi64c6fcgOfRxcxJCtT6eqvVLqZ
nZ3FdgVC3m0TBByku7OLGKUpbhubqk3xE7VC6UFFezLR9uzmpOqV3IZ0Lybd9EaF0ptK38ik
2zLbDck+XLLJbTxFoJI3NZlBTFOlvtzefmJkk7sKSn+qN6CJXmxTPTPXG3hdvw+iHdxsdsY6
zc6BYucGIafucduKZZnOUYmjIoOvI+IkEvsp10JF4puYkXCthxK5KUli9DU3R5QhVD+5if7Q
hp+JU7jaMLFTC3dDleFUcUQTxdSm8x/JtdPE6GvumyrpVDejie6oprq3cF2rGF1ESlxeG7tP
49J5NCiZVHd0E92sZtGTzZXHiNEsghzETXRCh5Y9ttnKWKqcY3ZmObOd2K7Rdm4abx/n151j
G/ZDZ6sy3ix2m6zKDj8NdksBHQTG0CwUlVvFVuxtAt0SzsyAVgdlotnZdNfksl3TPEYnBTZe
rTLZLA5oGMhYP9Bu9lGhPTX7ZgrrvrVN5ns9z1yo5IsRkt1t82tE1RRRcrbVnf0Do32vTG1u
4O2shxbCY1pA65gy3ey8duwCptlybN4RUD6qzGg+ZCFzW3pApF65s7mIjYn0CIjUKDPNTvS6
xNrGBbyeqRQ1tNmZTSy/OAK6hxViFrsE1hJTVJbVkmVVikVTowxVwroWAqp1irO5ZS4mMjwg
clyZZXYGbrCUMgPCdJfuJopbDLrO9vYE9I8o3uZDyLQPv8XIzPDeup/52gQd3ESt8b2dlkoE
u9NjlIg2hbSOYImIoCUi3Gbz0i1KpUzXTVttjXm1E7vkoYiQzUTo/gORSLFNiVsuktyaElWp
tBdbqVK50iFfDAsKSnPQ+Q8uk1ShpYjJMJlAwFUsNBk1wyQENJu1QANxa4Sp03rjJkKRrNLu
0mMSYoRyl0N3psckJiT0j6HCuiqUSW5XiTc9Jn/S5Biu4ggI9Y8RsNVOvHSNmIrLUyJoqj09
JmBCpjUvOzEj3meLL8j067rsZWp6egx7DoapxOuOpj2P4KMLQpozKYM/LMM9lhZPP7JvffCl
U9IE4rXLfjY0cQiSFyYrlDtddFY+f5HbpTld3hKBPwqjEk32q3ZiSYv3sW6gJ/Zf01XZW5IB
y5JPk2TqNf5jqTMjLR4l04rUaxWnSm5/C5pl7OumqnxobgSfoyp4Zc1JVxS/8GXkqzI1nmhO
GvnM/jx/SQnN5qyScD0m5XdzE4wAiAnYyZ4WMsfeSiq4XbFxsbk0SoEHglvdroz8xi4RPFIF
e+RHVyu4u2TaUkx96qVNElXwyl4y26XpdJEFOMsIMosM1cXjx/DDb0ydOp4OzOeOVgeMIYI4
ZYJhhosuqqrSUQIaKOSTWFGky61RpCnXwWzVW5pKy31YA3K6U9KbqarE7SKaIHuNThqii3nF
CK9G02BrACs2hvrDI6tEcNBCS6PPQQ0ollWPxB+ukopkv86foOI9xAk+N3umyiSAn2ESRMhh
NR1tocpgnY9uW4sRMDDYuOJAX4KPOoMujYZ9sqfGdHrq4BKaS2cOcdFvXDRrsW7ynZK3lD/q
xUag77QHaiRb6oZR+Iak/1SObIkbUg07W9AooNPPofERJ5Ay+kkT3K5SIrjlkhJwlEOQ6fCq
gKcf7k6a3/hjZdRe5hjiiBM0v90pSJpJ0IjXwTSpqW5B8usy8xtNw+4KwzU8A9NpqpJOV8CE
EdRgjalRSF0vaUIZyTAp0WIYDU1a6jvS07hRMzpb4T34QfOvHWKCoWQ2Lhvs+BTW0vGpdYsV
pU0lqyJQUSIK2QUIVJS2tKJEBh75s9Fe2/GqHCm2ovlUiRIjoXuBdS/MppUilB713EqHQjqj
cJ14fG56XlI62vOcEk2HlqzRloIpWZm0YJuoySalU+4UpXOlcoO5UeHqIoazzUt9n6F0DdSh
bpVKd6hDPZztDW/1rFR6+YuMetab1ulISS3xswXQbMzCG+lXoTb6ndLH3NwIK70sYR41WdUS
zaQIsnJTpRJjpn2XkgpN6VtILxnCbOxpIKU/vVLwFzWsSwd4DxH+sFrewjG6URkPCrgpspKu
CndT+3xv8L9drhuiNs2n0p2VmT1m0pTsVKOWe4VrDtqBRM/6dmXENfrEusHY9wZGkNjjpM0D
kjZbx+RnT/m/Giqem3/tVmxqQrPuoVWVXDRV8YrJC1NG5gSr1Ypd8caGjq67kemlNkZmdKXS
seHsV4v7eJT5379GCL7mnN44liKK/V47DQcHUcLMdqvPZ2n0wO8Y2jaaNpmU1jLf22axrV1m
drF40pQIsxjKHsxTTCyKWBPdILyqKO1uDab7iaWPyGuudqL+1c6VdTeRXOEhwIAEXgCbbQw0
YrFsy4uEMQYseWyw2YyxbDczA+NRZKvt7kGWVFrAcI5OnvIH8jrn5DfkNU/5AXnPe3KSnCyz
MMxCzslDcm9Vtbqr1S2VNB7hB/eZGdm+t25X3aq7fXU1rie4o4yLZif4yAo5ap7gY3CC+QHt
ggPqS+CMOXzglHxcbaPrSWnryVK6WCAn5tUDiU3QE4w+yfGSUxV1/p2b372WmZ8DOahvel/I
mB43tgWzadF6g9lnzZMJWL6SWlWClsRAYug2aHCZNlAGYn037EezqgiMmYbhn8A4Rw3KyOQw
/kNuFl2lCbBCU6NoYHFmdnFm6a6yfPfekjK7OPVw5nwA8o9bsFPPooFUdo261yFUJG5ntOov
ATn5U3NzTPySXT5tGIWUCgVWv6smlabtbH1N2um/uJ3O7Rw7peHHr+5d20yRQ2Cform2PXiP
m2u7W+3f4XroO8uYbrBDf3SFHDMPfZdlsd2ixR53E37CabQnbUZ7ihvt6Ypu/8l1e7JlRusO
adhst6tS/d4FBsgeKYN77asuTKCU2ASKiU1QEbbigv6egPrCoFkqow4z3tVsCjJ32LF0Fgra
C7P0CcTcc75jf2Ofe1+3LreohvfqO7jYXnBwVCNo7OZAJZ99UYgGRkdCNf7ppw7CHMUKc3EK
k/S/mdJmNBxQcJ7RAP1LAn+FiqZgvNLkZUREGZFmZFwRZVxpRsaoKGO0GRlXRRlXm5ExJsoY
a0bGNVHGtWZkjIsyxpuRcV2Ucb0ZGeERxyEbqSVFcILiQCfJJgMCEzcRDFLUbjxi0F/Y5z69
uZrPeenSeMHHyqXD9cqltix1j5VyiZZ8vFyiDm3VWTp20dKxm5eIx1fIiSDeHan7UIcQMQ7k
tTT98TQED7wW+EDdA9PJlNJp0jOv7qdAHDkzzy6GGD/lO6cDp6H3zOuUqCDxIBAZmn5epAaQ
uh+oyU1yQSRdRNIhIK0baS2DMfuSyHDZlIwASIH0itQgUn04qVIO1Ez6RHI/ktuQnE1Cfaul
QSUDIktIYDFSW8AyKLIMmXPUkwUjk9K2yDAyZCoMIyaDUSjQDSRhkSFi6u4ZjCdXkFioEEfN
FWaSRQjpV8WXj5krXNO1tWcFck0kj5uvhup9YwMvLq6LDDdM6SV6ZG6K1AmTuk6pUZEaM6ed
19YLZFIkfohEP9NKDkaTKXHN0zat5Uu4ObdEhtvI0M4YCqXVtTR8kBmRZxZ53seTs5Ymd+x6
02xYx10vrOPe/CK5XyYP7FjHnA3reGgF2vkyecQC7YLay4pVpZ9hLOBj6OQUio8rqy8V02ri
pjtZLJMlCxRZrgZFVPgTxW8e65X7ia5pnp/96idgTeJV3LZhTXwl7TBtS88dXnruBD2jR7Xr
+ZhNz12WnrvLkNpSPZ9QO0Q9b0HdyfV5qgxp7CrT2Af6Sac2eyoQ05l6PvNslpxD/2T6zPMr
JGD6zAvgfyyI6dif2ed7fwh633ntEe687HvCNbYfpobb8z5V5AHX/ThYJj5zP/wrmPmx/TgM
+3HEth9MfbAb3XgnGdXyzwyoSWn4o5l+u+p7BQuh3xbGrPmTmSXSWVnOX/nputOyrNbZJVA3
pVW/4PksTdhj/lka8zN5G9pkpgzKJjhX0Ea0d7I35scVRz1Lcyf2ZMVmgSQiIpgksFnUThb+
zZOF30h9UYxZqmsvQC1bLZRyqF+HrVodJIchjLcJ9/ntYi9Ah75f7cxkITnSclaN0Qku9UhQ
b9eR3CaQYYXYlKK3O/oCuoDzKCoRq1EDXEGClcHdwH5cmMEJx8iTdPGn1E6bm0IBBd6VYh/b
I87+DB16VvXb5neOpRk9+hn9rNomrus8TTLsAi+IAi9SgZfUNjxL1rjLMK5XGBcUx/XRcf2g
AUgw0SSzmfRLPqEBlj0E9T69X+2uZsAXDNL0wf6CYfEFI/QFYbWNnlHzCopEYNyVoD6sj+jh
KrMaBeJVk+hSSY6VivqgdUv+JblW7QDGBQdwvVgkN+J6xBr0FbkZ1EWmCWCKCp0FX2M/infg
mmSB60MYNxXXz1njfsDkQBR+C5hux/WjFtNrMuNkmgWmO3F9zGL6FhtTRKZ7wHQ/rndbTG8g
AdAnK20n5GFcH7Wo35F5p4hHwLQQ189bTN+TuJNpEZiW4raQr3da/G+J6uR/XCQfFcnHcX3A
YvsGu0NEticg9mnceVA/tcb8SFacYz6DMQmr7eEfPI796V3BPrxTwxv2mWUMHrBPO3fEph92
B22+5KDN77dplczl1lqlh43XB272WsCNj4FZPr/PxwGt+6VCUWGhiolXBpS0UQSSgkNMZAtG
MmzLDz9JYz8QC30+eyldvQQ54EdeSi3oR15KLfBHXkot+EdeSi0ASF5KLQhIXkotEEheSi0Y
SF5KLSDIJ4++fMXd1duWGbIj2NoM+GBOS0KRnje8fNN0JUWNKJvZlLFu4H2R0D6SLCqRkZHI
8Eh4ODymhMdvjEZuRCJD4dFryp2HywMRD3/2Nfvc/8fmisHqLKvx/PLdwVA0sQRGGwxl1ICh
DlN+5MRBbliUj91YIdkNjOpcN/JwBJ5j0wybohsu1ZHRtgQmN2zqQDafMjLJtDs0RSeKJuEK
TR2kcFnCA5Xy0wKFXnC4QlIWPccQqYIDkWIFToKWhxSRSomIlE9LGVz+FVH+qEDOMVCq4ACl
kMyEXxOFj7OlQ63+sgDrd4WkkAwn85mWcsWk/EBmXQspV1QKh9POvjV3XArJeeM5ohZTIp3i
Uj5qAFhVM1TKEFEpqDsMODz0dM6IS6eI1KFSLp1NphK5JBzLOyLDXQ4oAnkjny3lULv3xHfc
p8jXizwcDovngcgzR3lo6mXxPBR55un5M/g8HonzWKALSaa1PN+kuLhJi3SejL7JPAxZEkUs
20SkshmNqOL7H1NVcrq2Tj4Sh39MbQgb0dASeQsd+USU8YTqE7bLyLAbXfLUzmCH+T71gp9W
5hfJZ2WSsMNPv7TBT0nLl6+WyRrz5Sk1WIGfGP6Etqq80LW8pnB/pEygKx8hmumx18tkw8L5
9GqczzBxvs91reLaf2Cfv3jasghnL5zr56e/q3ROmO07NpQEJfljVe09QoMPbeFdAEbYnsWZ
uDqztBzkn6Hb04jIADtHelgSa2a/aoZ+pmxpLtbKPLHY0GBx6OICCj9G0cD09Az4HWVsKDwU
oe0HPCvmEJI0hqTcgpkX6PJC2FuYYa2ga/SvCsZdhZuFIjZKiUBIzE8/lKjtfZxgdUmF/F79
UDRUo3rqIFp+SXTqNT9qPa1LpkQYqZEWOXvVA/ZvoM522imZUgoG+B9WjDGekP2kYGK8/cel
9mHZprPyLUcyF1p2Vppqe/ht3eqZHwDa9EzFN15Cg5sP4b/9gZjPZ/0P9vjzU9smxJqqmaYJ
R8uonMB6HRT4SAmSr6ObaKLwSYqQL6Cb6aCQkyBfODfTPSEnoXbvhDNQ1zrKzfRVNFDYv+EX
UE1WtG63Dju6phVK2v1swvUK2qQtvz3rld+eg/xWoV+4tZxpwJbfXrAc58UyucQc52X1NM9v
6UyC/X22NJf0mjsGhXifldH2V2e0A2ZGG9J7K1v7HU8ztqtjrn7oqHm3eBgP69ZLJpRejE1l
spmXm9lSAb8wMVXC/A6/SoLlZId64GEyk9yAl3SabztSJEctJR4rw+5SJXYv/3dPJfrwpARs
yCMrMcPLz5Nk8ESpfvT3WwkIEPPJzIYWDIfoT6nsJv2AYisYCYVHRvqs61JpditTUWLCz5L3
rgGX29AhAZIb2qQblECEIdhbUWMvxPWKAgfgV28EDlkTQ2AgQbt6+kJKr4nw9YYUXqJE+Sdf
m5g6HTcNBc27cv6/56lTR+vSbPHGs37alLTSJjNvwgBD82a9WMwNaqRkPKdhBlPmQXRTtgS6
qG0VqQpuroFTgldGjUJ2cHz86vXBcMCS5J2BT6Wyq5pyJztnPNeUUTaE2QkWioq5khA/4ri8
bb7rsDTWTJbmNlr+bsNttPydhtto+RzMbbT8HYbbaPnUy220fNrlNlo+5XIbLX1H4ZvIZNlv
eOp83IXDD9wfILfFwb2D3yPzecvdw1jL3EN1r0d9D/HrHesh5rPUH9icxOdY5/Eg+QRiyza7
CkF7zXgLDwHyDsNDgLzP8BAg7zY8BMh7Dg8B8s7DQ4C8//AQIO9CPAS8Gy/yDa+f3rTMi7i1
OdX3I5OQIlfw3frQ3c8Nxpl58g5IlGtkylII3Y88jvyndWmm2HdUf/Pv79upQaRVaeZwcjOn
Z/PJ4VeVn8zvSQ4Xs7mmQ0pjcqUjTWNi5eNPY3Llw1JjcuWjVWNy5YNYY3LlY1tjcuVDXmNy
WxwJ/+d43tt9dp/dZ/fZfXaf3Wf32X12n+af/wMptUetAHgAAA==
--------------B3E3FDC4940D6BD680EDC7F6
Content-Type: text/plain; charset=us-ascii;
 name="Transaction.py"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="Transaction.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.
# 
##############################################################################
"""Transaction management

$Id: Transaction.py,v 1.30 2001/06/04 18:25:38 andreas Exp $"""
__version__='$Revision: 1.30 $'[11:-2]

import time, sys, struct, POSException
from struct import pack
from string import split, strip, join
from zLOG import LOG, ERROR, PANIC
from POSException import ConflictError

# Flag indicating whether certain errors have occurred.
hosed=0

class Transaction:
    'Simple transaction objects for single-threaded applications.'
    user=''
    description=''
    _connections=None
    _extension=None
    _sub=None # This is a subtrasaction flag

    # The _non_st_objects variable is either None or a list
    # of jars that do not support subtransactions. This is used to
    # manage non-subtransaction-supporting jars during subtransaction
    # commits and aborts to ensure that they are correctly committed
    # or aborted in the "outside" transaction.
    _non_st_objects=None
    
    def __init__(self, id=None):
        self._id=id
        self._objects=[]
        self._append=self._objects.append

    def _init(self):
        self._objects=[]
        self._append=self._objects.append
        self.user=self.description=''
        if self._connections:
            for c in self._connections.values(): c.close()
            del self._connections

    def sub(self):
        # Create a manually managed subtransaction for internal use
        r=self.__class__()
        r.user=self.user
        r.description=self.description
        r._extension=self._extension
        return r
        
    def __str__(self): return "%.3f\t%s" % (self._id or 0, self.user)

    def __del__(self):
        if self._objects: self.abort(freeme=0)

    def abort(self, subtransaction=0, freeme=1):
        '''Abort the transaction.

        This is called from the application.  This means that we haven\'t
        entered two-phase commit yet, so no tpc_ messages are sent.
        '''

        if subtransaction and (self._non_st_objects is not None):
            raise POSException.TransactionError, (
                """Attempted to abort a sub-transaction, but a participating
                data manager doesn't support partial abort.
                """)

        t=v=tb=None
        subj=self._sub
        subjars=()

        if not subtransaction:

            # Must add in any non-subtransaction supporting objects that
            # may have been stowed away from previous subtransaction
            # commits.
            if self._non_st_objects is not None:
                append=self._objects.append
                for object in self._non_st_objects:
                    append(object)
                self._non_st_objects = None

            if subj is not None:
                # Abort of top-level transaction after commiting
                # subtransactions.
                subjars=subj.values()
                self._sub=None

        try:
            # Abort the objects
            for o in self._objects:
                try:
                    j=getattr(o, '_p_jar', o)
                    if j is not None: j.abort(o, self)
                except:
                    if t is None:
                        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

        finally:
            tb=None
            del self._objects[:] # Clear registered
            if not subtransaction and freeme:
                if self._id is not None: free_transaction()
            else: self._init()

    def begin(self, info=None, subtransaction=None):
        '''Begin a new transaction.

        This aborts any transaction in progres.
        '''
        if self._objects: self.abort(subtransaction, 0)
        if info:
            info=split(info,'\t')
            self.user=strip(info[0])
            self.description=strip(join(info[1:],'\t'))

    def commit(self, subtransaction=None):
        'Finalize the transaction'

        global hosed
        
        objects=self._objects
        jars={}
        jarsv = None
        subj=self._sub
        subjars=()

        if subtransaction:
            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

        # If not a subtransaction, then we need to add any non-
        # subtransaction-supporting objects that may have been
        # stowed away during subtransaction commits to _objects.
        if (subtransaction is None) and (self._non_st_objects is not None):
            append=objects.append
            for object in self._non_st_objects:
                append(object)
            self._non_st_objects = None

        t=v=tb=None

        if (objects or subjars) and hosed:
            # Something really bad happened and we don't
            # trust the system state.
            raise POSException.TransactionError, (
                
                """A serious error, which was probably a system error,
                occurred in a previous database transaction.  This
                application may be in an invalid state and must be
                restarted before database updates can be allowed.

                Beware though that if the error was due to a serious
                system problem, such as a disk full condition, then
                the application may not come up until you deal with
                the system problem.  See your application log for
                information on the error that lead to this problem.
                """)

        _commit_succeeded = 0

        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:
                for o in objects:
                    j=getattr(o, '_p_jar', o)
                    if j is not None:
                        i=id(j)
                        if not jars.has_key(i):
                            jars[i]=j
                            if subtransaction:

                                # If a jar does not support subtransactions,
                                # we need to save it away to be committed in
                                # the outer transaction.
                                try: j.tpc_begin(self, subtransaction)
                                except TypeError:
                                    j.tpc_begin(self)

                                if hasattr(j, 'commit_sub'):
                                    subj[i]=j
                                else:
                                    if self._non_st_objects is None:
                                        self._non_st_objects = []
                                    self._non_st_objects.append(o)
                                    continue

                            else:
                                j.tpc_begin(self)
                        j.commit(o,self)
                    ncommitted=ncommitted+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)

                jarsv = jars.values()
                for jar in jarsv:
                    if not subtransaction:
                        try: jar=jar.tpc_vote
                        except: pass
                        else: jar(self) # last chance to bail

                try:
                    # Try to finish one jar, since we may be able to
                    # recover if the first one fails.
                    if jarsv:
                        jarsv[-1].tpc_finish(self) # This should never fail
                        jarsv.pop() # It didn't, so it's taken care of.
                except:
                    # Bug if it does, we need to keep track of it
                    LOG('ZODB', ERROR,
                        "A storage error occurred in the last phase of a "
                        "two-phase commit.  This shouldn\'t happen. ",
                        error=sys.exc_info())
                    raise

                try:
                    while jarsv:
                        jarsv[-1].tpc_finish(self) # This should never fail
                        jarsv.pop() # It didn't, so it's taken care of.
                except:                        
                    # Bug if it does, we need to yell FIRE!
                    # Someone finished, so don't allow any more
                    # work without at least a restart!
                    hosed=1
                    LOG('ZODB', PANIC,
                        "A storage error occurred in the last phase of a "
                        "two-phase commit.  This shouldn\'t happen. "
                        "The application may be in a hosed state, so "
                        "transactions will not be allowed to commit "
                        "until the site/storage is reset by a restart. ",
                        error=sys.exc_info())
                    raise
                
            except:
                t,v,tb=sys.exc_info()

                # Ugh, we got an got an error during commit, so we
                # have to clean up.

                # First, we have to abort any uncommitted objects.
                for o in objects[ncommitted:]:
                    try:
                        j=getattr(o, '_p_jar', o)
                        if j is not None: j.abort(o, self)
                    except: pass

                # Then, we unwind TPC for the jars that began it.
                if jarsv is None:
                    jarsv = jars.values()
                for j in jarsv:
                    try: j.tpc_abort(self) # This should never fail
                    except:     
                        LOG('ZODB', ERROR,
                            "A storage error occured during object abort "
                            "This shouldn\'t happen. ",
                            error=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

                raise t,v,tb

            _commit_succeeded = 1

        finally:
            tb=None

            if not _commit_succeeded:
                self.abort()

            del objects[:] # clear registered
            if not subtransaction and self._id is not None: free_transaction()

    def register(self,object):
        'Register the given object for transaction control.'
        self._append(object)

    def note(self, text):
        if self.description:
            self.description = "%s\n\n%s" % (self.description, strip(text))
        else: 
            self.description = strip(text)
    
    def setUser(self, user_name, path='/'):
        self.user="%s %s" % (path, user_name)

    def setExtendedInfo(self, name, value):
        ext=self._extension
        if ext is None:
            ext=self._extension={}
        ext[name]=value


############################################################################
# install get_transaction:

try:
    import thread

except:
    _t=Transaction(None)
    def get_transaction(_t=_t): return _t
    def free_transaction(_t=_t): _t.__init__()

else:
    _t={}
    def get_transaction(_id=thread.get_ident, _t=_t, get=_t.get, None=None):
        id=_id()
        t=get(id, None)
        if t is None: _t[id]=t=Transaction(id)
        return t

    def free_transaction(_id=thread.get_ident, _t=_t):
        id=_id()
        try: del _t[id]
        except KeyError: pass

    del thread

del _t

import __main__ 
__main__.__builtins__.get_transaction=get_transaction
    

--------------B3E3FDC4940D6BD680EDC7F6--