diff options
author | R. Tyler Ballance <tyler@slide.com> | 2009-07-16 15:25:04 -0700 |
---|---|---|
committer | R. Tyler Ballance <tyler@slide.com> | 2009-07-16 15:25:04 -0700 |
commit | 832a7c766de46cff23d6716ece9efd79db78cf5d (patch) | |
tree | 33e02b22a69491ea12241461ffdc9caa1f65d15b /cheetah/CacheRegion.py | |
parent | dc896aa348b7d5e4dbeed440c6ae8cf8ebdf2fdd (diff) | |
download | python-cheetah-832a7c766de46cff23d6716ece9efd79db78cf5d.tar.gz |
Rename the root package to "cheetah" instead of "src" to follow more conventional python package naming
Diffstat (limited to 'cheetah/CacheRegion.py')
-rw-r--r-- | cheetah/CacheRegion.py | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/cheetah/CacheRegion.py b/cheetah/CacheRegion.py new file mode 100644 index 0000000..dd0d099 --- /dev/null +++ b/cheetah/CacheRegion.py @@ -0,0 +1,136 @@ +# $Id: CacheRegion.py,v 1.3 2006/01/28 04:19:30 tavis_rudd Exp $ +''' +Cache holder classes for Cheetah: + +Cache regions are defined using the #cache Cheetah directive. Each +cache region can be viewed as a dictionary (keyed by cacheRegionID) +handling at least one cache item (the default one). It's possible to add +cacheItems in a region by using the `varyBy` #cache directive parameter as +in the following example:: + #def getArticle + this is the article content. + #end def + + #cache varyBy=$getArticleID() + $getArticle($getArticleID()) + #end cache + +The code above will generate a CacheRegion and add new cacheItem for each value +of $getArticleID(). +''' + +try: + from hashlib import md5 +except ImportError: + from md5 import md5 + +import time +import Cheetah.CacheStore + +class CacheItem(object): + ''' + A CacheItem is a container storing: + + - cacheID (string) + - refreshTime (timestamp or None) : last time the cache was refreshed + - data (string) : the content of the cache + ''' + + def __init__(self, cacheItemID, cacheStore): + self._cacheItemID = cacheItemID + self._cacheStore = cacheStore + self._refreshTime = None + self._expiryTime = 0 + + def hasExpired(self): + return (self._expiryTime and time.time() > self._expiryTime) + + def setExpiryTime(self, time): + self._expiryTime = time + + def getExpiryTime(self): + return self._expiryTime + + def setData(self, data): + self._refreshTime = time.time() + self._cacheStore.set(self._cacheItemID, data, self._expiryTime) + + def getRefreshTime(self): + return self._refreshTime + + def getData(self): + assert self._refreshTime + return self._cacheStore.get(self._cacheItemID) + + def renderOutput(self): + """Can be overridden to implement edge-caching""" + return self.getData() or "" + + def clear(self): + self._cacheStore.delete(self._cacheItemID) + self._refreshTime = None + +class _CacheDataStoreWrapper(object): + def __init__(self, dataStore, keyPrefix): + self._dataStore = dataStore + self._keyPrefix = keyPrefix + + def get(self, key): + return self._dataStore.get(self._keyPrefix+key) + + def delete(self, key): + self._dataStore.delete(self._keyPrefix+key) + + def set(self, key, val, time=0): + self._dataStore.set(self._keyPrefix+key, val, time=time) + +class CacheRegion(object): + ''' + A `CacheRegion` stores some `CacheItem` instances. + + This implementation stores the data in the memory of the current process. + If you need a more advanced data store, create a cacheStore class that works + with Cheetah's CacheStore protocol and provide it as the cacheStore argument + to __init__. For example you could use + Cheetah.CacheStore.MemcachedCacheStore, a wrapper around the Python + memcached API (http://www.danga.com/memcached). + ''' + _cacheItemClass = CacheItem + + def __init__(self, regionID, templateCacheIdPrefix='', cacheStore=None): + self._isNew = True + self._regionID = regionID + self._templateCacheIdPrefix = templateCacheIdPrefix + if not cacheStore: + cacheStore = Cheetah.CacheStore.MemoryCacheStore() + self._cacheStore = cacheStore + self._wrappedCacheDataStore = _CacheDataStoreWrapper( + cacheStore, keyPrefix=templateCacheIdPrefix+':'+regionID+':') + self._cacheItems = {} + + def isNew(self): + return self._isNew + + def clear(self): + " drop all the caches stored in this cache region " + for cacheItemId in self._cacheItems.keys(): + cacheItem = self._cacheItems[cacheItemId] + cacheItem.clear() + del self._cacheItems[cacheItemId] + + def getCacheItem(self, cacheItemID): + """ Lazy access to a cacheItem + + Try to find a cache in the stored caches. If it doesn't + exist, it's created. + + Returns a `CacheItem` instance. + """ + cacheItemID = md5(str(cacheItemID)).hexdigest() + + if not self._cacheItems.has_key(cacheItemID): + cacheItem = self._cacheItemClass( + cacheItemID=cacheItemID, cacheStore=self._wrappedCacheDataStore) + self._cacheItems[cacheItemID] = cacheItem + self._isNew = False + return self._cacheItems[cacheItemID] |