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 @@
import Globals
import App
from types import StringTypes
from AccessControl import getSecurityManager, ClassSecurityInfo
from Products.CMFCore.utils import getToolByName
from Products.DCWorkflow.DCWorkflow import DCWorkflowDefinition
......@@ -195,26 +196,31 @@ class InteractionWorkflowDefinition (DCWorkflowDefinition, ActiveObject):
return
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.
"""
return
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,
allowing veto by exception. Unless an exception is thrown, either
a notifySuccess() or notifyException() can be expected later on.
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
# to be compatible with DCWorkflow
# A better approach consists in extending DCWorkflow
kw = kw.copy()
kw['workflow_method_args'] = args
if kw is None:
kw = {'workflow_method_args' : args}
else:
kw = kw.copy()
kw['workflow_method_args'] = args
filtered_transition_list = []
for t_id in transition_list:
......@@ -236,11 +242,12 @@ class InteractionWorkflowDefinition (DCWorkflowDefinition, ActiveObject):
return filtered_transition_list
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.
'''
if not transition_list: return
if type(transition_list) in StringTypes:
return
kw = kw.copy()
kw['workflow_method_args'] = args
......
......@@ -43,8 +43,8 @@ class Reindex(Method):
# This is required to call the method form the Web
# More information at http://www.zope.org/Members/htrd/howto/FunctionTemplate
func_code = func_code()
func_code.co_varnames = ('self',)
func_code.co_argcount = 1
func_code.co_varnames = ('self', 'value') # XXX - This part should be configurable at instanciation
func_code.co_argcount = 2
func_defaults = ()
def __init__(self, id, accessor_id):
......@@ -75,6 +75,7 @@ class Dummy(Reindex):
self._id = id
self.__name__ = id
self._accessor_id = accessor_id
self.func_code = getattr(instance, self._accessor_id).func_code
def __call__(self, instance, *args, **kw):
method = getattr(instance, self._accessor_id)
......
......@@ -51,11 +51,11 @@ class Setter(Method):
# This is required to call the method form the Web
# More information at http://www.zope.org/Members/htrd/howto/FunctionTemplate
func_code = func_code()
func_code.co_varnames = ('self','value')
func_code.co_varnames = ('self', 'value')
func_code.co_argcount = 2
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.__name__ = id
self._key = key
......
......@@ -51,7 +51,7 @@ class DefaultSetter(Method):
func_code.co_argcount = 2
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.__name__ = id
self._key = key
......@@ -140,7 +140,7 @@ class SetSetter(Method):
func_code.co_argcount = 2
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.__name__ = id
self._key = key
......@@ -227,6 +227,10 @@ class DefaultGetter(Method):
default = args[0]
else:
default = self._default
if default and len(default):
default = default[0]
else:
default = None
list_value = getattr(instance, self._storage_id, None)
if list_value is not None:
if self._is_tales_type:
......@@ -284,7 +288,9 @@ class ListGetter(Method):
else:
return 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__)
......
This diff is collapsed.
This diff is collapsed.
......@@ -13,6 +13,7 @@
##############################################################################
from zLOG import LOG, WARNING
from types import StringTypes
# Make sure Interaction Workflows are called even if method not wrapped
......@@ -29,11 +30,17 @@ from Products.CMFCore.utils import _getAuthenticatedUser
from Products.ERP5Type.Cache import CachingMethod
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
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)
if sdef is None:
raise WorkflowException, 'Object is in an undefined state'
......@@ -54,7 +61,7 @@ def DCWorkflowDefinition_notifyWorkflowMethod(self, ob, method_id, args=None, 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,
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
'''
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.
'''
......
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