Commit 8d4c2a58 authored by Jean-Paul Smets's avatar Jean-Paul Smets

This megapatch changes the way accessors are generated. Instead of generating...

This megapatch changes the way accessors are generated. Instead of generating all accessors for each portal type, we only generate tuples which are put in a kind of tuple cache. The idea is to minimise the number of objects which are created and use objects which are as small as possible. Then, the next time aq_dynamic is invoked, we dynamically create a new accessor instance based on the parameters provided in the tuple. This way, it is possible to reduce the memory footprint of ERP5 by 200 MB at least and create only those accessors which are needed. 
In addition, accessors are now generated per portal_type and per class. This way, if the class of a portal type changes in a system, different accessors are generated and there is no risk of falling into a problem of "first argument of method XXX must be of type YYY".
The downside is currently a possible speed decrease of 2-3%.

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@17606 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent f22b5a0e
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
import Globals import Globals
import App import App
from types import StringTypes
from AccessControl import getSecurityManager, ClassSecurityInfo from AccessControl import getSecurityManager, ClassSecurityInfo
from Products.CMFCore.utils import getToolByName from Products.CMFCore.utils import getToolByName
from Products.DCWorkflow.DCWorkflow import DCWorkflowDefinition from Products.DCWorkflow.DCWorkflow import DCWorkflowDefinition
...@@ -195,26 +196,31 @@ class InteractionWorkflowDefinition (DCWorkflowDefinition, ActiveObject): ...@@ -195,26 +196,31 @@ class InteractionWorkflowDefinition (DCWorkflowDefinition, ActiveObject):
return return
security.declarePrivate('notifyWorkflowMethod') security.declarePrivate('notifyWorkflowMethod')
def notifyWorkflowMethod(self, ob, action, args=None, kw=None, transition_list=None): def notifyWorkflowMethod(self, ob, transition_list, args=None, kw=None):
""" """
InteractionWorkflow is stateless. Thus, this function should do nothing. InteractionWorkflow is stateless. Thus, this function should do nothing.
""" """
return return
security.declarePrivate('notifyBefore') security.declarePrivate('notifyBefore')
def notifyBefore(self, ob, action, args=None, kw=None, transition_list=None): def notifyBefore(self, ob, transition_list, args=None, kw=None):
''' '''
Notifies this workflow of an action before it happens, Notifies this workflow of an action before it happens,
allowing veto by exception. Unless an exception is thrown, either allowing veto by exception. Unless an exception is thrown, either
a notifySuccess() or notifyException() can be expected later on. a notifySuccess() or notifyException() can be expected later on.
The action usually corresponds to a method name. The action usually corresponds to a method name.
''' '''
if not transition_list: return if type(transition_list) in StringTypes:
return
# Wrap args into kw since this is the only way # Wrap args into kw since this is the only way
# to be compatible with DCWorkflow # to be compatible with DCWorkflow
# A better approach consists in extending DCWorkflow # A better approach consists in extending DCWorkflow
kw = kw.copy() if kw is None:
kw['workflow_method_args'] = args kw = {'workflow_method_args' : args}
else:
kw = kw.copy()
kw['workflow_method_args'] = args
filtered_transition_list = [] filtered_transition_list = []
for t_id in transition_list: for t_id in transition_list:
...@@ -236,11 +242,12 @@ class InteractionWorkflowDefinition (DCWorkflowDefinition, ActiveObject): ...@@ -236,11 +242,12 @@ class InteractionWorkflowDefinition (DCWorkflowDefinition, ActiveObject):
return filtered_transition_list return filtered_transition_list
security.declarePrivate('notifySuccess') security.declarePrivate('notifySuccess')
def notifySuccess(self, ob, action, result, args=None, kw=None, transition_list=None): def notifySuccess(self, ob, transition_list, result, args=None, kw=None):
''' '''
Notifies this workflow that an action has taken place. Notifies this workflow that an action has taken place.
''' '''
if not transition_list: return if type(transition_list) in StringTypes:
return
kw = kw.copy() kw = kw.copy()
kw['workflow_method_args'] = args kw['workflow_method_args'] = args
......
...@@ -43,8 +43,8 @@ class Reindex(Method): ...@@ -43,8 +43,8 @@ class Reindex(Method):
# This is required to call the method form the Web # This is required to call the method form the Web
# More information at http://www.zope.org/Members/htrd/howto/FunctionTemplate # More information at http://www.zope.org/Members/htrd/howto/FunctionTemplate
func_code = func_code() func_code = func_code()
func_code.co_varnames = ('self',) func_code.co_varnames = ('self', 'value') # XXX - This part should be configurable at instanciation
func_code.co_argcount = 1 func_code.co_argcount = 2
func_defaults = () func_defaults = ()
def __init__(self, id, accessor_id): def __init__(self, id, accessor_id):
...@@ -75,6 +75,7 @@ class Dummy(Reindex): ...@@ -75,6 +75,7 @@ class Dummy(Reindex):
self._id = id self._id = id
self.__name__ = id self.__name__ = id
self._accessor_id = accessor_id self._accessor_id = accessor_id
self.func_code = getattr(instance, self._accessor_id).func_code
def __call__(self, instance, *args, **kw): def __call__(self, instance, *args, **kw):
method = getattr(instance, self._accessor_id) method = getattr(instance, self._accessor_id)
......
...@@ -51,11 +51,11 @@ class Setter(Method): ...@@ -51,11 +51,11 @@ class Setter(Method):
# This is required to call the method form the Web # This is required to call the method form the Web
# More information at http://www.zope.org/Members/htrd/howto/FunctionTemplate # More information at http://www.zope.org/Members/htrd/howto/FunctionTemplate
func_code = func_code() func_code = func_code()
func_code.co_varnames = ('self','value') func_code.co_varnames = ('self', 'value')
func_code.co_argcount = 2 func_code.co_argcount = 2
func_defaults = () func_defaults = ()
def __init__(self, id, key, property_type, reindex=1, storage_id=None): def __init__(self, id, key, property_type, storage_id=None, reindex=1):
self._id = id self._id = id
self.__name__ = id self.__name__ = id
self._key = key self._key = key
......
...@@ -51,7 +51,7 @@ class DefaultSetter(Method): ...@@ -51,7 +51,7 @@ class DefaultSetter(Method):
func_code.co_argcount = 2 func_code.co_argcount = 2
func_defaults = () func_defaults = ()
def __init__(self, id, key, property_type, reindex=1, storage_id=None): def __init__(self, id, key, property_type, storage_id=None, reindex=1):
self._id = id self._id = id
self.__name__ = id self.__name__ = id
self._key = key self._key = key
...@@ -140,7 +140,7 @@ class SetSetter(Method): ...@@ -140,7 +140,7 @@ class SetSetter(Method):
func_code.co_argcount = 2 func_code.co_argcount = 2
func_defaults = () func_defaults = ()
def __init__(self, id, key, property_type, reindex=1, storage_id=None): def __init__(self, id, key, property_type, storage_id=None, reindex=1):
self._id = id self._id = id
self.__name__ = id self.__name__ = id
self._key = key self._key = key
...@@ -227,6 +227,10 @@ class DefaultGetter(Method): ...@@ -227,6 +227,10 @@ class DefaultGetter(Method):
default = args[0] default = args[0]
else: else:
default = self._default default = self._default
if default and len(default):
default = default[0]
else:
default = None
list_value = getattr(instance, self._storage_id, None) list_value = getattr(instance, self._storage_id, None)
if list_value is not None: if list_value is not None:
if self._is_tales_type: if self._is_tales_type:
...@@ -284,7 +288,9 @@ class ListGetter(Method): ...@@ -284,7 +288,9 @@ class ListGetter(Method):
else: else:
return list_value return list_value
return list(list_value) return list(list_value)
return default if default is None:
return None # nothing was defined as default so None is the right value
return list(default) # Make sure we return a list rather than a tuple
psyco.bind(__call__) psyco.bind(__call__)
......
This diff is collapsed.
This diff is collapsed.
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
############################################################################## ##############################################################################
from zLOG import LOG, WARNING from zLOG import LOG, WARNING
from types import StringTypes
# Make sure Interaction Workflows are called even if method not wrapped # Make sure Interaction Workflows are called even if method not wrapped
...@@ -29,11 +30,17 @@ from Products.CMFCore.utils import _getAuthenticatedUser ...@@ -29,11 +30,17 @@ from Products.CMFCore.utils import _getAuthenticatedUser
from Products.ERP5Type.Cache import CachingMethod from Products.ERP5Type.Cache import CachingMethod
from sets import ImmutableSet from sets import ImmutableSet
def DCWorkflowDefinition_notifyWorkflowMethod(self, ob, method_id, args=None, kw=None, transition_list=None): def DCWorkflowDefinition_notifyWorkflowMethod(self, ob, transition_list, args=None, kw=None):
''' '''
Allows the system to request a workflow action. This method Allows the system to request a workflow action. This method
must perform its own security checks. must perform its own security checks.
''' '''
if type(transition_list) in StringTypes:
method_id = transition_list
elif len(transition_list) == 1:
method_id = transition_list[0]
else:
raise ValueError('WorkflowMethod should be attached to exactly 1 transition per DCWorkflow instance.')
sdef = self._getWorkflowStateOf(ob) sdef = self._getWorkflowStateOf(ob)
if sdef is None: if sdef is None:
raise WorkflowException, 'Object is in an undefined state' raise WorkflowException, 'Object is in an undefined state'
...@@ -54,7 +61,7 @@ def DCWorkflowDefinition_notifyWorkflowMethod(self, ob, method_id, args=None, kw ...@@ -54,7 +61,7 @@ def DCWorkflowDefinition_notifyWorkflowMethod(self, ob, method_id, args=None, kw
activate_kw = {} activate_kw = {}
ob.reindexObject(activate_kw=activate_kw) ob.reindexObject(activate_kw=activate_kw)
def DCWorkflowDefinition_notifyBefore(self, ob, action, args=None, kw=None, transition_list=None): def DCWorkflowDefinition_notifyBefore(self, ob, transition_list, args=None, kw=None):
''' '''
Notifies this workflow of an action before it happens, Notifies this workflow of an action before it happens,
allowing veto by exception. Unless an exception is thrown, either allowing veto by exception. Unless an exception is thrown, either
...@@ -63,7 +70,7 @@ def DCWorkflowDefinition_notifyBefore(self, ob, action, args=None, kw=None, tran ...@@ -63,7 +70,7 @@ def DCWorkflowDefinition_notifyBefore(self, ob, action, args=None, kw=None, tran
''' '''
pass pass
def DCWorkflowDefinition_notifySuccess(self, ob, action, result, args=None, kw=None, transition_list=None): def DCWorkflowDefinition_notifySuccess(self, ob, transition_list, result, args=None, kw=None):
''' '''
Notifies this workflow that an action has taken place. Notifies this workflow that an action has taken place.
''' '''
......
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