[Erp5-report] r24556 - /erp5/trunk/products/ERP5Type/patches/CMFCoreSkinnable.py
nobody at svn.erp5.org
nobody at svn.erp5.org
Wed Nov 12 13:59:17 CET 2008
Author: vincent
Date: Wed Nov 12 13:59:14 2008
New Revision: 24556
URL: http://svn.erp5.org?rev=24556&view=rev
Log:
Prevent SkinDataCleanup from deleting SKINDATA entries which were created after the one it was targeted at. (See code comment for complete explanation)
Modified:
erp5/trunk/products/ERP5Type/patches/CMFCoreSkinnable.py
Modified: erp5/trunk/products/ERP5Type/patches/CMFCoreSkinnable.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5Type/patches/CMFCoreSkinnable.py?rev=24556&r1=24555&r2=24556&view=diff
==============================================================================
--- erp5/trunk/products/ERP5Type/patches/CMFCoreSkinnable.py [utf8] (original)
+++ erp5/trunk/products/ERP5Type/patches/CMFCoreSkinnable.py [utf8] Wed Nov 12 13:59:14 2008
@@ -13,7 +13,7 @@
##############################################################################
from Products.CMFCore import Skinnable
-from Products.CMFCore.Skinnable import SKINDATA, superGetAttr, SkinDataCleanup, SkinnableObjectManager
+from Products.CMFCore.Skinnable import SKINDATA, superGetAttr, SkinnableObjectManager
from thread import get_ident
from zLOG import LOG, WARNING, DEBUG
from Acquisition import aq_base
@@ -134,7 +134,7 @@
SKINDATA[tid] = (skinname, {'portal_skins': None}, {})
REQUEST = getattr(self, 'REQUEST', None)
if REQUEST is not None:
- REQUEST._hold(SkinDataCleanup(tid))
+ REQUEST._hold(SkinDataCleanup(tid, SKINDATA[tid]))
def CMFCoreSkinnableSkinnableObjectManager_getSkin(self, name=None):
"""
@@ -154,3 +154,35 @@
from Products.CMFCore.PortalObject import PortalObjectBase
PortalObjectBase.__getattr__ = CMFCoreSkinnableSkinnableObjectManager___getattr__
+# Redefine SkinDataCleanup completely.
+# This class is designed to remove entries from SKINDATA dictionnary, to avoid
+# keeping references to persistent objects besides transaction boundaries.
+# This cleanup is triggered by deletion of SkinDataCleanup instance, which
+# happens after corresponding REQUEST instance is deleted (because of '_hold'
+# mechanism).
+# But because of the lag which exists between REQUEST deletion and
+# SkinDataCleanup deletion (due to garbage collection), it sometimes deletes a
+# new SKINDATA entry, unrelated to the intended one. This leaves a system with
+# no SKINDATA entry for current thread, leading to errors.
+# A case where it's easy to trigger such error is CMFActivity's REQUEST
+# separation mechanism, where one request is created for each single activity.
+
+class SkinDataCleanup:
+ def __init__(self, tid, skindata):
+ self.tid = tid
+ self.skindata_id = self.hashSkinData(skindata)
+
+ def __del__(self):
+ tid = self.tid
+ skindata = SKINDATA.get(tid)
+ if skindata is not None:
+ if self.hashSkinData(skindata) == self.skindata_id:
+ try:
+ # Entry might have already disapeared. Ignore.
+ del SKINDATA[tid]
+ except KeyError:
+ pass
+
+ def hashSkinData(self, skindata):
+ return id(skindata)
+
More information about the Erp5-report
mailing list