##################################################
# SPYCE - Python-based HTML Scripting
# Copyright (c) 2002 Rimon Barr.
#
# Refer to spyce.py
# CVS: $Id: spyceCache.py 1095 2006-08-09 22:28:10Z ellisj $
##################################################
import spyceLock, spyceUtil
import os, string
from md5 import md5
try: from cPickle import dumps,loads
except: from pickle import dumps,loads
__doc__ = '''Caching related functionality.'''
# rimtodo: specify some sort of cache size limit
##################################################
# Generic cache
#
class cache:
"Generic cache"
def __getitem__(self, key):
raise 'not implemented'
def __setitem__(self, key, value):
raise 'not implemented'
def __delitem__(self, key):
raise 'not implemented'
def keys(self):
raise 'not implemented'
def has_key(self, key):
raise 'not implemented'
##################################################
# Storage caches
#
class memoryCache(cache):
"In-memory cache"
def __init__(self, infoStr=None):
self.cache = {}
self.info = infoStr
def __getitem__(self, key):
return self.cache[key]
def __setitem__(self, key, value):
self.cache[key]=value
def __delitem__(self, key):
del self.cache[key]
def keys(self):
return self.cache.keys()
def has_key(self, key):
return self.cache.has_key(key)
class fileCache(cache):
"File-based cache"
def __init__(self, infoStr):
self._cachedir = string.strip(infoStr)
def _filename(self, key):
return os.path.join(self._cachedir, self._encodeKey(key))
def __getitem__(self, key):
f = None
try:
try:
f = open(self._filename(key), 'rb')
return loads(f.read())
finally:
if f: f.close()
except IOError: pass
except EOFError: pass
raise KeyError()
def __setitem__(self, key, value):
try:
if self[key]==value: return
except KeyError: pass
f = None
try:
f = open(self._filename(key), 'wb')
f.write(dumps(value, -1))
finally:
if f: f.close()
def __delitem__(self, key):
filename = self._filename(key)
if os.path.exists(filename):
os.remove(filename)
def keys(keys):
raise 'not implemented'
def has_key(self, key):
try:
self[key]
return 1
except KeyError:
return 0
def _encodeKey(self, key):
return 'spyceCache-' + md5(str(key)).hexdigest()
##################################################
# Policy caches
#
#rimtodo:
##################################################
# Semantic cache
#
class semanticCache(cache):
"""Cache that knows how to validate and generate its own data. Note, that the
cache stores elements as (validity, data) tuples. The valid is a function
invoked as valid(key,validity), returning a boolean; and generate is a
function invoked as generate(key) returning (validity, data). The get()
method returns only the data."""
def __init__(self, cache, valid, generate, lock=None):
self.valid = valid
self.generate = generate
self.cache = cache
if lock is None:
lock = spyceLock.dummyLock()
self.lock = lock
def get(self, key):
"Get (or generate) a cache element."
try:
self.lock.acquire()
except:
# must be a file lock, rlock won't raise
raise "couldn't lock %s -- did you set tmp to be a writable directory in your spyceconf?\n\nexact exception was %s" % (self.lock.name, spyceUtil.exceptionString())
try:
if self.cache is None:
return self.generate(key)[1]
else:
if not key in self.cache or not self.valid(key, self.cache[key][0]):
self.cache[key] = self.generate(key)
return self.cache[key][1]
finally:
self.lock.release()
def purge(self, key):
"Remove a cache element, if it exists."
if self.cache.has_key(key):
del self.cache[key]
# standard dictionary methods
def __getitem__(self, key):
return self.get(key)
def __delitem__(self, key):
return self.purge(key)
def has_key(self, key):
if self.cache:
return self.cache.has_key()
else:
return 0
def keys(self):
if self.cache:
return self.cache.keys()
else:
return []
def values(self):
if self.cache:
return map(lambda x: x[1], self.cache.values())
else:
return []
def clear(self):
if self.cache:
self.cache.clear()
|