From 347b899bd79dd8c33b47f52444dcb9d9c554c2cb Mon Sep 17 00:00:00 2001 From: Arnaud Fontaine <arnaud.fontaine@nexedi.com> Date: Tue, 7 Feb 2012 18:00:42 +0900 Subject: [PATCH] Avoid costly checking if Component modules are synchronized on __getattribute__. --- product/ERP5Type/Tool/ComponentTool.py | 60 +++++++++++++-------- product/ERP5Type/dynamic/component_class.py | 27 ---------- product/ERP5Type/dynamic/dynamic_module.py | 4 +- 3 files changed, 40 insertions(+), 51 deletions(-) diff --git a/product/ERP5Type/Tool/ComponentTool.py b/product/ERP5Type/Tool/ComponentTool.py index f2cbbe2793..364a73bfe2 100644 --- a/product/ERP5Type/Tool/ComponentTool.py +++ b/product/ERP5Type/Tool/ComponentTool.py @@ -30,12 +30,14 @@ import transaction from AccessControl import ClassSecurityInfo -from Products.ERP5Type.Tool.BaseTool import BaseTool from Products.ERP5Type import Permissions +from Products.ERP5Type.Tool.BaseTool import BaseTool +from Products.ERP5Type.Base import Base from Products.ERP5Type.TransactionalVariable import getTransactionalVariable from zLOG import LOG, INFO, WARNING +_last_sync = -1 class ComponentTool(BaseTool): """ This tool provides methods to load the the different types @@ -50,38 +52,52 @@ class ComponentTool(BaseTool): security.declareObjectProtected(Permissions.AccessContentsInformation) security.declareProtected(Permissions.ModifyPortalContent, 'reset') - def reset(self, is_sync=False): + def reset(self, force=True): """ XXX-arnau: global reset """ - LOG("ERP5Type.Tool.ComponentTool", INFO, "Resetting Components") - - import erp5.component - portal = self.getPortalObject() - if not is_sync: + # XXX-arnau: copy/paste from portal_type_class, but is this really + # necessary as even for Portal Type classes, synchronizeDynamicModules + # seems to always called with force=True? + global last_sync + if force: + # hard invalidation to force sync between nodes portal.newCacheCookie('component_classes') - erp5.component._last_reset = portal.getCacheCookie('component_classes') + last_sync = portal.getCacheCookie('component_classes') + else: + cookie = portal.getCacheCookie('component_classes') + if cookie == last_sync: + type_tool.resetDynamicDocumentsOnceAtTransactionBoundary() + return + last_sync = cookie + + LOG("ERP5Type.Tool.ComponentTool", INFO, "Resetting Components") type_tool = portal.portal_types - container_type_info = type_tool.getTypeInfo(self.getPortalType()) - for content_type in container_type_info.getTypeAllowedContentTypeList(): - module_name = content_type.split(' ')[0].lower() + allowed_content_type_list = type_tool.getTypeInfo( + self.getPortalType()).getTypeAllowedContentTypeList() - try: - module = getattr(erp5.component, module_name) - # XXX-arnau: not everything is defined yet... - except AttributeError: - pass - else: - for name in module.__dict__.keys(): - if name[0] != '_': - LOG("ERP5Type.Tool.ComponentTool", INFO, - "Resetting erp5.component.%s.%s" % (module_name, name)) + import erp5.component - delattr(module, name) + with Base.aq_method_lock: + for content_type in allowed_content_type_list: + module_name = content_type.split(' ')[0].lower() + + try: + module = getattr(erp5.component, module_name) + # XXX-arnau: not everything is defined yet... + except AttributeError: + pass + else: + for name in module.__dict__.keys(): + if name[0] != '_': + LOG("ERP5Type.Tool.ComponentTool", INFO, + "Resetting erp5.component.%s.%s" % (module_name, name)) + + delattr(module, name) type_tool.resetDynamicDocumentsOnceAtTransactionBoundary() diff --git a/product/ERP5Type/dynamic/component_class.py b/product/ERP5Type/dynamic/component_class.py index 5b2261c0c0..dc74ec8bca 100644 --- a/product/ERP5Type/dynamic/component_class.py +++ b/product/ERP5Type/dynamic/component_class.py @@ -28,33 +28,6 @@ from Products.ERP5.ERP5Site import getSite from types import ModuleType - -class ComponentModule(ModuleType): - _resetting = False - _last_reset = -1 - - def __getattribute__(self, name): - """ - Synchronize between ZEO clients - - XXX-arnau: surely bad from a performance POV and not thread-safe - """ - if name[0] == '_' or self._resetting: - return super(ComponentModule, self).__getattribute__(name) - - import erp5.component - site = getSite() - cookie = site.getCacheCookie('component_classes') - if self._last_reset == -1: - self._last_reset = site.getCacheCookie('component_classes') - elif cookie != self._last_reset: - self._resetting = True - site.portal_components.reset(is_sync=True) - self._resetting = False - - return super(ComponentModule, self).__getattribute__(name) - -from types import ModuleType from zLOG import LOG, INFO def generateComponentClassWrapper(namespace, portal_type): diff --git a/product/ERP5Type/dynamic/dynamic_module.py b/product/ERP5Type/dynamic/dynamic_module.py index efd8a64263..d000784e5c 100644 --- a/product/ERP5Type/dynamic/dynamic_module.py +++ b/product/ERP5Type/dynamic/dynamic_module.py @@ -122,9 +122,9 @@ def initializeDynamicModules(): loadTempPortalTypeClass) # Components - from component_class import ComponentModule, generateComponentClassWrapper + from component_class import generateComponentClassWrapper - erp5.component = ComponentModule("erp5.component") + erp5.component = ModuleType("erp5.component") sys.modules["erp5.component"] = erp5.component erp5.component.extension = registerDynamicModule( -- 2.30.9