preferences: clear cache in a more clever way
Introduce something similar to "cache cookie", but more suitable for preferences that depend both on the site configuration and user preferences. We store for each user a value in _preference_cache and we modify this value each time user change his user preference. This value is then used part of the a cache key. The same mechanism happen with a global value for site and group preferences. See _getCacheId docstring for more details. This way, when one user modify their preference this does not reset cache for every user. Because we have proper invalidation, increase the case duration by using erp5_ui_short instead of erp5_ui_long This is applied to both preference methods and to templates documents inside preferences. test_system_preference_value_prefererred_clear_cache_disabled is updated to use another preference name, because it was same as in a previous test, so that we don't have test isolation problems.
Showing
... | @@ -41,6 +41,7 @@ from Products.ERP5Type.Cache import CachingMethod | ... | @@ -41,6 +41,7 @@ from Products.ERP5Type.Cache import CachingMethod |
from Products.ERP5Type.Utils import convertToUpperCase | from Products.ERP5Type.Utils import convertToUpperCase | ||
from Products.ERP5Type.TransactionalVariable import getTransactionalVariable | from Products.ERP5Type.TransactionalVariable import getTransactionalVariable | ||
from Products.ERP5Form import _dtmldir | from Products.ERP5Form import _dtmldir | ||
from BTrees.OIBTree import OIBTree | |||
_marker = object() | _marker = object() | ||
... | @@ -83,10 +84,11 @@ class PreferenceMethod(Method): | ... | @@ -83,10 +84,11 @@ class PreferenceMethod(Method): |
return default | return default | ||
_getPreference = CachingMethod(_getPreference, | _getPreference = CachingMethod(_getPreference, | ||
id='%s.%s' % (self._preference_cache_id, | id='%s.%s' % (self._preference_cache_id, | ||
getSecurityManager().getUser().getId()), | instance.getPortalObject().portal_preferences._getCacheId()), | ||
cache_factory='erp5_ui_short') | cache_factory='erp5_ui_long') | ||
return _getPreference(default, *args, **kw) | return _getPreference(default, *args, **kw) | ||
class PreferenceTool(BaseTool): | class PreferenceTool(BaseTool): | ||
""" | """ | ||
PreferenceTool manages User Preferences / User profiles. | PreferenceTool manages User Preferences / User profiles. | ||
... | @@ -199,6 +201,35 @@ class PreferenceTool(BaseTool): | ... | @@ -199,6 +201,35 @@ class PreferenceTool(BaseTool): |
Note that this preference may be read only. """ | Note that this preference may be read only. """ | ||
return self._getActivePreferenceByPortalType('Preference') | return self._getActivePreferenceByPortalType('Preference') | ||
security.declareProtected(Permissions.View, 'clearCache') | |||
def clearCache(self, preference): | |||
""" clear cache when a preference is modified. | |||
This is called by an interaction workflow on preferences. | |||
""" | |||
self._getCacheId() # initialize _preference_cache if needed. | |||
if preference.getPriority() == Priority.USER: | |||
user_id = getSecurityManager().getUser().getId() | |||
self._preference_cache[user_id] = \ | |||
self._preference_cache.get(user_id, 0) + 1 | |||
self._preference_cache[None] = self._preference_cache.get(None, 0) + 1 | |||
def _getCacheId(self): | |||
"""Return a cache id for preferences. | |||
We use: | |||
- user_id: because preferences are always different by user | |||
- self._preference_cache[user_id] which is increased everytime a user | |||
preference is modified | |||
- self._preference_cache[None] which is increased everytime a global | |||
preference is modified | |||
|
|||
""" | |||
user_id = getSecurityManager().getUser().getId() | |||
try: | |||
self._preference_cache | |||
except AttributeError: | |||
self._preference_cache = OIBTree() | |||
return self._preference_cache.get(None), self._preference_cache.get(user_id), user_id | |||
security.declareProtected(Permissions.View, 'getActiveUserPreference') | security.declareProtected(Permissions.View, 'getActiveUserPreference') | ||
def getActiveUserPreference(self) : | def getActiveUserPreference(self) : | ||
""" returns the current user preference for the user. | """ returns the current user preference for the user. | ||
... | @@ -244,9 +275,10 @@ class PreferenceTool(BaseTool): | ... | @@ -244,9 +275,10 @@ class PreferenceTool(BaseTool): |
for doc in pref.contentValues(portal_type=portal_type) : | for doc in pref.contentValues(portal_type=portal_type) : | ||
acceptable_template_list.append(doc.getRelativeUrl()) | acceptable_template_list.append(doc.getRelativeUrl()) | ||
return acceptable_template_list | return acceptable_template_list | ||
_getDocumentTemplateList = CachingMethod(_getDocumentTemplateList, | _getDocumentTemplateList = CachingMethod( | ||
'portal_preferences.getDocumentTemplateList', | _getDocumentTemplateList, | ||
cache_factory='erp5_ui_short') | 'portal_preferences.getDocumentTemplateList.{}'.format(self._getCacheId()), | ||
cache_factory='erp5_ui_long') | |||
allowed_content_types = map(lambda pti: pti.id, | allowed_content_types = map(lambda pti: pti.id, | ||
folder.allowedContentTypes()) | folder.allowedContentTypes()) | ||
... | ... |