Commit 9e783585 authored by Arnaud Fontaine's avatar Arnaud Fontaine

Use aq_method_lock rather than defining separate locks for ZODB Components.

Before, there was a separate lock for generating the registry and loading a
Component which was wrong as the latter use the registry. Also, as reset was
using aq_method_lock, modules could be reset while being loaded at the same
time.
parent 2fb1b3f1
...@@ -34,6 +34,7 @@ import sys ...@@ -34,6 +34,7 @@ import sys
import threading import threading
from Products.ERP5.ERP5Site import getSite from Products.ERP5.ERP5Site import getSite
from Products.ERP5Type.Base import Base
from types import ModuleType from types import ModuleType
from zLOG import LOG, INFO, BLATHER from zLOG import LOG, INFO, BLATHER
...@@ -72,8 +73,6 @@ class ComponentDynamicPackage(ModuleType): ...@@ -72,8 +73,6 @@ class ComponentDynamicPackage(ModuleType):
self._namespace_prefix = namespace + '.' self._namespace_prefix = namespace + '.'
self._portal_type = portal_type self._portal_type = portal_type
self.__version_suffix_len = len('_version') self.__version_suffix_len = len('_version')
self._load_module_lock = threading.RLock()
self._registry_generate_lock = threading.RLock()
self.__registry_dict = {} self.__registry_dict = {}
# Add this module to sys.path for future imports # Add this module to sys.path for future imports
...@@ -110,7 +109,7 @@ class ComponentDynamicPackage(ModuleType): ...@@ -110,7 +109,7 @@ class ComponentDynamicPackage(ModuleType):
# this is only done at startup or upon reset, moreover using the Catalog # this is only done at startup or upon reset, moreover using the Catalog
# is too risky as it lags behind and depends upon objects being # is too risky as it lags behind and depends upon objects being
# reindexed # reindexed
with self._registry_generate_lock: with Base.aq_method_lock:
for component in component_tool.objectValues(portal_type=self._portal_type): for component in component_tool.objectValues(portal_type=self._portal_type):
# Only consider modified or validated states as state transition will # Only consider modified or validated states as state transition will
# be handled by component_validation_workflow which will take care of # be handled by component_validation_workflow which will take care of
...@@ -184,7 +183,7 @@ class ComponentDynamicPackage(ModuleType): ...@@ -184,7 +183,7 @@ class ComponentDynamicPackage(ModuleType):
return version_package return version_package
def load_module(self, fullname): def __load_module(self, fullname):
""" """
Load a module with given fullname (see PEP 302) if it's not Load a module with given fullname (see PEP 302) if it's not
already in sys.modules. It is assumed that imports are filtered already in sys.modules. It is assumed that imports are filtered
...@@ -233,16 +232,12 @@ class ComponentDynamicPackage(ModuleType): ...@@ -233,16 +232,12 @@ class ComponentDynamicPackage(ModuleType):
except AttributeError: except AttributeError:
pass pass
else: else:
with self._load_module_lock:
setattr(self._getVersionPackage(version), name, module) setattr(self._getVersionPackage(version), name, module)
return module return module
module_fullname_alias = self._namespace + '.' + name module_fullname_alias = self._namespace + '.' + name
module_fullname = '%s.%s_version.%s' % (self._namespace, version, name) module_fullname = '%s.%s_version.%s' % (self._namespace, version, name)
with self._load_module_lock:
module = ModuleType(module_fullname, component.getDescription()) module = ModuleType(module_fullname, component.getDescription())
# The module *must* be in sys.modules before executing the code in case # The module *must* be in sys.modules before executing the code in case
...@@ -275,6 +270,14 @@ class ComponentDynamicPackage(ModuleType): ...@@ -275,6 +270,14 @@ class ComponentDynamicPackage(ModuleType):
return module return module
def load_module(self, fullname):
"""
Make sure that loading module is thread-safe using aq_method_lock to make
sure that modules do not disappear because of an ongoing reset
"""
with Base.aq_method_lock:
return self.__load_module(fullname)
def reset(self, sub_package=None): def reset(self, sub_package=None):
""" """
Reset the content of the current package and its version package as well Reset the content of the current package and its version package as well
......
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