1
# $Id: CacheRegion.py,v 1.3 2006/01/28 04:19:30 tavis_rudd Exp $
2
"""Cache holder classes for Cheetah:
4
Cache regions are defined using the #cache Cheetah directive. Each
5
cache region can be viewed as a dictionary (keyed by cacheRegionID)
6
handling at least one cache item (the default one). It's possible to add
7
cacheItems in a region by using the `varyBy` #cache directive parameter as
8
in the following example::
10
this is the article content.
13
#cache varyBy=$getArticleID()
14
$getArticle($getArticleID())
17
The code above will generate a CacheRegion and add new cacheItem for each value
21
================================================================================
22
Author: Tavis Rudd <tavis@damnsimple.com> and Philippe Normand <phil@base-art.net>
23
Version: $Revision: 1.3 $
24
Start Date: 2005/06/20
25
Last Revision Date: $Date: 2006/01/28 04:19:30 $
27
__author__ = "Tavis Rudd <tavis@damnsimple.com> and Philippe Normand <phil@base-art.net>"
28
__revision__ = "$Revision: 1.3 $"[11:-2]
31
from time import time as currentTime
32
from Cheetah.CacheStore import MemoryCacheStore
35
"""A CacheItem is a container storing:
38
- refreshTime (timestamp or None) : last time the cache was refreshed
39
- data (string) : the content of the cache
42
def __init__(self, cacheItemID, cacheStore):
43
self._cacheItemID = cacheItemID
44
self._cacheStore = cacheStore
45
self._refreshTime = None
49
return (self._expiryTime and currentTime() > self._expiryTime)
51
def setExpiryTime(self, time):
52
self._expiryTime = time
54
def getExpiryTime(self):
55
return self._expiryTime
57
def setData(self, data):
58
self._refreshTime = currentTime()
59
self._cacheStore.set(self._cacheItemID, data, self._expiryTime)
61
def getRefreshTime(self):
62
return self._refreshTime
65
assert self._refreshTime
66
return self._cacheStore.get(self._cacheItemID)
68
def renderOutput(self):
69
"""Can be overridden to implement edge-caching"""
70
return self.getData() or ""
73
self._cacheStore.delete(self._cacheItemID)
74
self._refreshTime = None
76
class _CacheDataStoreWrapper:
77
def __init__(self, dataStore, keyPrefix):
78
self._dataStore = dataStore
79
self._keyPrefix = keyPrefix
82
return self._dataStore.get(self._keyPrefix+key)
84
def delete(self, key):
85
self._dataStore.delete(self._keyPrefix+key)
87
def set(self, key, val, time=0):
88
self._dataStore.set(self._keyPrefix+key, val, time=time)
91
""" A `CacheRegion` stores some `CacheItem` instances.
93
This implementation stores the data in the memory of the current process.
94
If you need a more advanced data store, create a cacheStore class that works
95
with Cheetah's CacheStore protocol and provide it as the cacheStore argument
96
to __init__. For example you could use
97
Cheetah.CacheStore.MemcachedCacheStore, a wrapper around the Python
98
memcached API (http://www.danga.com/memcached).
100
_cacheItemClass = CacheItem
102
def __init__(self, regionID, templateCacheIdPrefix='', cacheStore=None):
104
self._regionID = regionID
105
self._templateCacheIdPrefix = templateCacheIdPrefix
107
cacheStore = MemoryCacheStore()
108
self._cacheStore = cacheStore
109
self._wrappedCacheDataStore = _CacheDataStoreWrapper(
110
cacheStore, keyPrefix=templateCacheIdPrefix+':'+regionID+':')
111
self._cacheItems = {}
117
" drop all the caches stored in this cache region "
118
for cacheItemId in self._cacheItems.keys():
119
cacheItem = self._cacheItems[cacheItemId]
121
del self._cacheItems[cacheItemId]
123
def getCacheItem(self, cacheItemID):
124
""" Lazy access to a cacheItem
126
Try to find a cache in the stored caches. If it doesn't
129
Returns a `CacheItem` instance.
131
cacheItemID = md5.new(str(cacheItemID)).hexdigest()
133
if not self._cacheItems.has_key(cacheItemID):
134
cacheItem = self._cacheItemClass(
135
cacheItemID=cacheItemID, cacheStore=self._wrappedCacheDataStore)
136
self._cacheItems[cacheItemID] = cacheItem
138
return self._cacheItems[cacheItemID]