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]
34 from time
import time
as currentTime
35 from Cheetah
.CacheStore
import MemoryCacheStore
38 """A CacheItem is a container storing:
41 - refreshTime (timestamp or None) : last time the cache was refreshed
42 - data (string) : the content of the cache
45 def __init__(self
, cacheItemID
, cacheStore
):
46 self
._cacheItemID
= cacheItemID
47 self
._cacheStore
= cacheStore
48 self
._refreshTime
= None
52 return (self
._expiryTime
and currentTime() > self
._expiryTime
)
54 def setExpiryTime(self
, time
):
55 self
._expiryTime
= time
57 def getExpiryTime(self
):
58 return self
._expiryTime
60 def setData(self
, data
):
61 self
._refreshTime
= currentTime()
62 self
._cacheStore
.set(self
._cacheItemID
, data
, self
._expiryTime
)
64 def getRefreshTime(self
):
65 return self
._refreshTime
68 assert self
._refreshTime
69 return self
._cacheStore
.get(self
._cacheItemID
)
71 def renderOutput(self
):
72 """Can be overridden to implement edge-caching"""
73 return self
.getData() or ""
76 self
._cacheStore
.delete(self
._cacheItemID
)
77 self
._refreshTime
= None
79 class _CacheDataStoreWrapper
:
80 def __init__(self
, dataStore
, keyPrefix
):
81 self
._dataStore
= dataStore
82 self
._keyPrefix
= keyPrefix
85 return self
._dataStore
.get(self
._keyPrefix
+key
)
87 def delete(self
, key
):
88 self
._dataStore
.delete(self
._keyPrefix
+key
)
90 def set(self
, key
, val
, time
=0):
91 self
._dataStore
.set(self
._keyPrefix
+key
, val
, time
=time
)
94 """ A `CacheRegion` stores some `CacheItem` instances.
96 This implementation stores the data in the memory of the current process.
97 If you need a more advanced data store, create a cacheStore class that works
98 with Cheetah's CacheStore protocol and provide it as the cacheStore argument
99 to __init__. For example you could use
100 Cheetah.CacheStore.MemcachedCacheStore, a wrapper around the Python
101 memcached API (http://www.danga.com/memcached).
103 _cacheItemClass
= CacheItem
105 def __init__(self
, regionID
, templateCacheIdPrefix
='', cacheStore
=None):
107 self
._regionID
= regionID
108 self
._templateCacheIdPrefix
= templateCacheIdPrefix
110 cacheStore
= MemoryCacheStore()
111 self
._cacheStore
= cacheStore
112 self
._wrappedCacheDataStore
= _CacheDataStoreWrapper(
113 cacheStore
, keyPrefix
=templateCacheIdPrefix
+':'+regionID
+':')
114 self
._cacheItems
= {}
120 " drop all the caches stored in this cache region "
121 for cacheItemId
in self
._cacheItems
.keys():
122 cacheItem
= self
._cacheItems
[cacheItemId
]
124 del self
._cacheItems
[cacheItemId
]
126 def getCacheItem(self
, cacheItemID
):
127 """ Lazy access to a cacheItem
129 Try to find a cache in the stored caches. If it doesn't
132 Returns a `CacheItem` instance.
134 cacheItemID
= hashlib
.md5(str(cacheItemID
)).hexdigest()
136 if not self
._cacheItems
.has_key(cacheItemID
):
137 cacheItem
= self
._cacheItemClass
(
138 cacheItemID
=cacheItemID
, cacheStore
=self
._wrappedCacheDataStore
)
139 self
._cacheItems
[cacheItemID
] = cacheItem
141 return self
._cacheItems
[cacheItemID
]