[Erp5-report] r35216 nicolas - /erp5/trunk/products/ERP5/mixin/cached_convertable.py
nobody at svn.erp5.org
nobody at svn.erp5.org
Wed May 12 15:23:19 CEST 2010
Author: nicolas
Date: Wed May 12 15:23:15 2010
New Revision: 35216
URL: http://svn.erp5.org?rev=35216&view=rev
Log:
Follow cached_convertable interface by adding following
public methods:
- getConversion
- getConversionMd5
- getConversionDate
- getConversionSize
Modified:
erp5/trunk/products/ERP5/mixin/cached_convertable.py
Modified: erp5/trunk/products/ERP5/mixin/cached_convertable.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/mixin/cached_convertable.py?rev=35216&r1=35215&r2=35216&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/mixin/cached_convertable.py [utf8] (original)
+++ erp5/trunk/products/ERP5/mixin/cached_convertable.py [utf8] Wed May 12 15:23:15 2010
@@ -35,11 +35,28 @@
from Products.ERP5Type import Permissions
from Products.CMFCore.utils import getToolByName
from Products.ERP5Type.Cache import DEFAULT_CACHE_SCOPE
+from Products.ERP5Type.TransactionalVariable import getTransactionalVariable
+from OFS.Image import Pdata, Image as OFSImage
+from DateTime import DateTime
def makeSortedTuple(kw):
items = kw.items()
items.sort()
return tuple(items)
+
+def hashPdataObject(data):
+ """Pdata objects are iterable, use this feature strongly
+ to minimize memory footprint.
+ """
+ md5_hash = md5.new()
+ next = chunk = data.next
+ if next is None:
+ md5_hash.update(data.data)
+ while next is not None:
+ chunk = next
+ md5_hash.update(chunk)
+ next = data.next
+ return md5_hash.hexdigest()
class CachedConvertableMixin:
"""
@@ -78,7 +95,7 @@
cache_tool.updateCache()
return cache_tool.getRamCacheRoot().get(cache_factory_name)
- def _getCacheKey(self):
+ def _getCacheKey(self, **kw):
"""
Returns the key to use for the cache entries. For now,
use the object uid.
@@ -87,27 +104,14 @@
http://pypi.python.org/pypi/uuid/ to generate
a uuid stored as private property.
"""
- return '%s:%s' % (aq_base(self).getUid(), self.getRevision())
+ format_cache_id = str(makeSortedTuple(kw)).\
+ translate(string.maketrans('', ''), '[]()<>\'", ')
+ return '%s:%s:%s' % (aq_base(self).getUid(), self.getRevision(),
+ format_cache_id)
security.declareProtected(Permissions.View, 'hasConversion')
def hasConversion(self, **kw):
"""
- If you want to get conversion cache value if exists, please write
- the code like:
-
- try:
- mime, data = getConversion(**kw)
- except KeyError:
- ...
-
- instead of:
-
- if self.hasConversion(**kw):
- mime, data = self.getConversion(**kw)
- else:
- ...
-
- for better performance.
"""
try:
self.getConversion(**kw)
@@ -116,70 +120,115 @@
return False
security.declareProtected(Permissions.ModifyPortalContent, 'setConversion')
- def setConversion(self, data, mime=None, calculation_time=None, **kw):
- """
- """
- cache_id = '%s%s' % (self._getCacheKey(), self.generateCacheId(**kw))
+ def setConversion(self, data, mime=None, date=None, **kw):
+ """
+ """
+ cache_id = self._getCacheKey(**kw)
+ if data is None:
+ cached_value = None
+ conversion_md5 = None
+ size = 0
+ elif isinstance(data, Pdata):
+ cached_value = aq_base(data)
+ conversion_md5 = hashPdataObject(cached_value)
+ size = len(cached_value)
+ elif isinstance(data, OFSImage):
+ cached_value = data
+ conversion_md5 = md5.new(str(data.data)).hexdigest()
+ size = len(data.data)
+ else:
+ cached_value = data
+ conversion_md5 = md5.new(cached_value).hexdigest()
+ size = len(cached_value)
+ if date is None:
+ date = DateTime()
+ stored_data_dict = {'content_md5': self.getContentMd5(),
+ 'conversion_md5': conversion_md5,
+ 'mime': mime,
+ 'data': cached_value,
+ 'date': date,
+ 'size': size}
if self.isTempObject():
if getattr(aq_base(self), 'temp_conversion_data', None) is None:
self.temp_conversion_data = {}
- self.temp_conversion_data[cache_id] = (mime, aq_base(data))
+ self.temp_conversion_data[cache_id] = stored_data_dict
return
cache_factory = self._getCacheFactory()
cache_duration = cache_factory.cache_duration
- if data is not None:
- for cache_plugin in cache_factory.getCachePluginList():
- cache_plugin.set(cache_id, DEFAULT_CACHE_SCOPE,
- (self.getContentMd5(), mime, aq_base(data)),
- calculation_time=calculation_time,
- cache_duration=cache_duration)
-
- security.declareProtected(Permissions.View, 'getConversion')
- def getConversion(self, **kw):
- """
- """
- cache_id = '%s%s' % (self._getCacheKey(), self.generateCacheId(**kw))
+ # The purpose of this transaction cache is to help calls
+ # to the same cache value in the same transaction.
+ tv = getTransactionalVariable(None)
+ tv[cache_id] = stored_data_dict
+ for cache_plugin in cache_factory.getCachePluginList():
+ cache_plugin.set(cache_id, DEFAULT_CACHE_SCOPE,
+ stored_data_dict, cache_duration=cache_duration)
+
+ security.declareProtected(Permissions.View, '_getConversionDataDict')
+ def _getConversionDataDict(self, **kw):
+ """
+ """
+ cache_id = self._getCacheKey(**kw)
if self.isTempObject():
return getattr(aq_base(self), 'temp_conversion_data', {})[cache_id]
+ # The purpose of this cache is to help calls to the same cache value
+ # in the same transaction.
+ tv = getTransactionalVariable(None)
+ try:
+ return tv[cache_id]
+ except KeyError:
+ pass
for cache_plugin in self._getCacheFactory().getCachePluginList():
cache_entry = cache_plugin.get(cache_id, DEFAULT_CACHE_SCOPE)
if cache_entry is not None:
- data_list = cache_entry.getValue()
- if data_list:
- md5sum, mime, data = data_list
- if md5sum != self.getContentMd5():
+ data_dict = cache_entry.getValue()
+ if data_dict:
+ content_md5 = data_dict['content_md5']
+ if content_md5 != self.getContentMd5():
raise KeyError, 'Conversion cache key is compromised for %r' % cache_id
- return mime, data
+ # Fill transactional cache in order to help
+ # querying real cache during same transaction
+ tv[cache_id] = data_dict
+ return data_dict
raise KeyError, 'Conversion cache key does not exists for %r' % cache_id
+
+ security.declareProtected(Permissions.View, 'getConversion')
+ def getConversion(self, **kw):
+ """
+ """
+ cached_dict = self._getConversionDataDict(**kw)
+ return cached_dict['mime'], cached_dict['data']
security.declareProtected(Permissions.View, 'getConversionSize')
def getConversionSize(self, **kw):
"""
"""
try:
- mime, data = self.getConversion(**kw)
- return len(data)
+ return self._getConversionDataDict(**kw)['size']
except KeyError:
+ # If conversion doesn't exists return 0
return 0
- def generateCacheId(self, **kw):
- """Generate proper cache id based on **kw.
- Function inspired from ERP5Type.Cache
- """
- return str(makeSortedTuple(kw)).translate(string.maketrans('', ''), '[]()<>\'", ')
+ security.declareProtected(Permissions.View, 'getConversionDate')
+ def getConversionDate(self, **kw):
+ """
+ """
+ return self._getConversionDataDict(**kw)['date']
+
+ security.declareProtected(Permissions.View, 'getConversionMd5')
+ def getConversionMd5(self, **kw):
+ """
+ """
+ return self._getConversionDataDict(**kw)['conversion_md5']
security.declareProtected(Permissions.ModifyPortalContent, 'updateContentMd5')
def updateContentMd5(self):
"""Update md5 checksum from the original file
-
- XXX-JPS - this method is not part of any interfacce.
- should it be public or private. It is called
- by some interaction workflow already. Is
- it general or related to caching only ?
- """
- data = self.getData()
+ """
+ mime, data = self.convert(None)
if data is not None:
- data = str(data) # Usefull for Pdata
- self._setContentMd5(md5.new(data).hexdigest()) # Reindex is useless
+ if isinstance(data, Pdata):
+ self._setContentMd5(hashPdataObject(aq_base(data)))
+ else:
+ self._setContentMd5(md5.new(data).hexdigest()) # Reindex is useless
else:
self._setContentMd5(None)
More information about the Erp5-report
mailing list