Commit 45686651 authored by Ivan Tyagov's avatar Ivan Tyagov Committed by Julien Muchembled

Introduce consistent set / get API amonst Cache Factory, Cache Bag and

different kinds of Cache Plugins.
This API change allows developer to create complex cache structures which
can contain arbitrary set of Cache Plugins and / or Cache Bags (Cache Factory).
Extend Cache Factory so it can return RAM based Cache Plugin instance by its Uid.
Fix tests to reflect changes.
parent e3f2a0a2
......@@ -200,6 +200,14 @@ class CacheFactory:
return cp
return None
def getCachePluginByUid(self, uid):
""" get cache plugin by its Uid """
for cp in self.cache_plugins:
if uid == cp.uid:
return cp
return None
def clearCache(self):
""" clear cache for this cache factory """
for cp in self.cache_plugins:
......
......@@ -94,10 +94,11 @@ class BaseCache(object):
## Time interval (s) to check for expired objects
cache_expire_check_interval = 60
def __init__(self, params={}):
def __init__(self, uid, params={}):
self._next_cache_expire_check_at = time()
self._cache_hit_count = 0
self._cache_miss_count = 0
self.uid = uid
def markCacheHit(self, delta=1):
""" Mark a read operation from cache """
......
......@@ -55,14 +55,14 @@ class DistributedRamCache(BaseCache):
interfaces.ICachePlugin
)
def __init__(self, params={}):
def __init__(self, uid, params={}):
self._servers = params.get('server', '')
self._expiration_time = params.get('expiration_time', 0)
self._server_max_key_length = params.get('server_max_key_length', 250)
self._server_max_value_length = params.get('server_max_value_length', 1024*1024)
self._debug_level = params.get('debug_level', 0)
self._key_prefix = params.get('key_prefix', '')
BaseCache.__init__(self)
BaseCache.__init__(self, uid)
def initCacheStorage(self):
""" Init cache storage """
......
......@@ -59,9 +59,9 @@ class RamCache(BaseCache):
cache_expire_check_interval = 300
def __init__(self, params={}):
def __init__(self, uid, params={}):
self._cache_dict = {}
BaseCache.__init__(self)
BaseCache.__init__(self, uid)
def initCacheStorage(self):
""" Init cache storage """
......
......@@ -58,6 +58,7 @@ class CacheFactory(XMLObject):
, PropertySheet.SimpleItem
, PropertySheet.Folder
, PropertySheet.CacheFactory
, PropertySheet.SortIndex
)
def getCacheUid(self):
......@@ -71,9 +72,34 @@ class CacheFactory(XMLObject):
assert relative_url[:14] == 'portal_caches/'
return relative_url[14:]
def getCachePluginList(self):
security.declareProtected(Permissions.AccessContentsInformation, 'get')
def get(self, cache_id, default=None):
"""
Get value or return default from all contained Cache Bag
or Cache Plugin.
"""
cache_plugin_list = self.getCachePluginList(list(self.allowed_types) + ['ERP5 Cache Bag'])
for cache_plugin in cache_plugin_list:
value = cache_plugin.get(cache_id, default)
if value is not None:
return value
return default
security.declareProtected(Permissions.AccessContentsInformation, 'set')
def set(self, cache_id, value):
"""
Set value to all contained cache plugin or cache bag.
"""
cache_plugin_list = self.getCachePluginList(list(self.allowed_types) + ['ERP5 Cache Bag'])
for cache_plugin in cache_plugin_list:
cache_plugin.set(cache_id, value)
def getCachePluginList(self, allowed_types=None):
""" get ordered list of installed cache plugins in ZODB """
cache_plugins = self.objectValues(self.allowed_types)
if allowed_types is None:
# fall back to default ones
allowed_types = self.allowed_types
cache_plugins = self.objectValues(allowed_types)
cache_plugins = map(None, cache_plugins)
cache_plugins.sort(key=lambda x: x.getIntIndex(0))
return cache_plugins
......@@ -99,5 +125,5 @@ class CacheFactory(XMLObject):
def clearCache(self):
""" clear cache for this cache factory """
for cp in self.getRamCacheFactory().getCachePluginList():
for cp in self.getRamCacheFactoryPluginList():
cp.clearCache()
......@@ -31,8 +31,9 @@ from AccessControl import ClassSecurityInfo
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Type import PropertySheet
from Products.ERP5Type import Permissions
from Products.ERP5Type.mixin.cache_provider import CacheProviderMixIn
class DistributedRamCache(XMLObject):
class DistributedRamCache(CacheProviderMixIn, XMLObject):
"""
DistributedRamCache is a Zope (persistent) representation of
the Distributed RAM Cache real cache plugin object.
......
......@@ -32,8 +32,9 @@ from AccessControl import ClassSecurityInfo
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Type import PropertySheet
from Products.ERP5Type import Permissions
from Products.ERP5Type.mixin.cache_provider import CacheProviderMixIn
class RamCache(XMLObject):
class RamCache(CacheProviderMixIn, XMLObject):
"""
RamCache is a Zope (persistent) representation of
the RAM based real cache plugin object.
......
......@@ -69,8 +69,9 @@ class CacheTool(BaseTool):
def getRamCachePlugin(cp):
cp_meta_type = cp.meta_type
uid = cp.getCacheUid()
if cp_meta_type == 'ERP5 Ram Cache':
return RamCache()
return RamCache(uid)
if cp_meta_type == 'ERP5 Distributed Ram Cache':
## even thougn we have such plugin in ZODB that doens't mean
## we have corresponding memcache module installed
......@@ -84,7 +85,7 @@ class CacheTool(BaseTool):
'server_max_key_length': memcached_plugin.getServerMaxKeyLength(),
'server_max_value_length': memcached_plugin.getServerMaxValueLength(),
'key_prefix': getattr(self, 'erp5_site_global_id', '')}
return DistributedRamCache(init_dict)
return DistributedRamCache(uid, init_dict)
rd = {}
for cf in self.objectValues(['ERP5 Cache Factory', 'ERP5 Cache Bag']):
......
......@@ -36,7 +36,7 @@ class ICachePlugin(Interface):
"""CachePlugin Interface Specification
"""
def __init__(params={}):
def __init__(uid, params={}):
"""Initialise default values
"""
......
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2012 Nexedi SA and Contributors. All Rights Reserved.
# Ivan Tyagov <ivan@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions
from Products.ERP5Type.Cache import DEFAULT_CACHE_SCOPE
class CacheProviderMixIn:
"""
Generic Cache Plugin set / get API implementation.
"""
security = ClassSecurityInfo()
def _getRamCachePlugin(self):
"""
Get RAM based cache plugin for this ZODB cache plugin.
"""
return self.getParentValue().getRamCacheFactory().getCachePluginByUid(self.getCacheUid())
security.declareProtected(Permissions.AccessContentsInformation, 'get')
def get(self, cache_id, default=None):
"""
Get value from cache plugin.
"""
cache_plugin = self._getRamCachePlugin()
value = cache_plugin.get(cache_id, DEFAULT_CACHE_SCOPE, default)
if value is not None:
value = value.getValue()
return value
security.declareProtected(Permissions.AccessContentsInformation, 'set')
def set(self, cache_id, value):
"""
Set value to cache plugin.
"""
cache_duration = self.getParentValue().getRamCacheFactory().cache_duration
cache_plugin = self._getRamCachePlugin()
cache_plugin.set(cache_id, DEFAULT_CACHE_SCOPE, value, cache_duration)
def getCacheUid(self):
"""
Get a common Cache Factory / Cache Bag UID in this
case relative to portal_caches.
It's required to use relative url (i.e. mainly ID) due
to CachingMethod legacy.
"""
relative_url = self.getRelativeUrl()
assert relative_url[:14] == 'portal_caches/'
return relative_url[14:]
......@@ -50,8 +50,9 @@ class TestRamCache(ERP5TypeTestCase):
return "Cache"
def afterSetUp(self):
self.cache_plugins = (RamCache(),
DistributedRamCache({'server': '127.0.0.1:11211',
self.cache_plugins = (RamCache('ram_cache'),
DistributedRamCache('distributed_ram_cache',
{'server': '127.0.0.1:11211',
'debug_level': 7,
'server_max_key_length': 250,
'server_max_value_length': 1048576,}),
......
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