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
]