new redic cache, thanks nihlod

This commit is contained in:
Massimo Di Pierro
2012-01-29 15:17:14 -06:00
parent b3b5c35267
commit 77e8889398
2 changed files with 74 additions and 35 deletions
+1 -1
View File
@@ -1 +1 @@
Version 1.99.4 (2012-01-29 15:16:03) stable Version 1.99.4 (2012-01-29 15:17:09) stable
+73 -34
View File
@@ -4,21 +4,24 @@ Released under web2py license because includes gluon/cache.py source code
""" """
import redis import redis
from redis.exceptions import ConnectionError
from gluon import current from gluon import current
from gluon.cache import CacheAbstract from gluon.cache import CacheAbstract
import cPickle as pickle import cPickle as pickle
import time import time
import re import re
import logging
import thread import thread
logger = logging.getLogger("web2py.cache.redis")
locker = thread.allocate_lock() locker = thread.allocate_lock()
def RedisCache(*args, **vars): def RedisCache(*args, **vars):
""" """
Usage example: put in models Usage example: put in models
from gluon.contrib.redis import RedisCache from gluon.contrib.redis_cache import RedisCache
cache.redis = RedisCache('localhost:6379',db=None, debug=True) cache.redis = RedisCache('localhost:6379',db=None, debug=True)
cache.redis.stats() cache.redis.stats()
@@ -42,14 +45,17 @@ def RedisCache(*args, **vars):
class RedisClient(object): class RedisClient(object):
meta_storage = {} meta_storage = {}
MAX_RETRIES = 5
RETRIES = 0
def __init__(self, server='localhost:6379', db=None, debug=False): def __init__(self, server='localhost:6379', db=None, debug=False):
host,port = (address.split(':')+['6379'])[:2] self.server = server
self.db = db or 0
host,port = (self.server.split(':')+['6379'])[:2]
port = int(port) port = int(port)
self.request=current.request self.request = current.request
self.debug = debug self.debug = debug
if request: if self.request:
app = request.application app = self.request.application
else: else:
app = '' app = ''
@@ -61,36 +67,69 @@ class RedisClient(object):
}} }}
else: else:
self.storage = self.meta_storage[app] self.storage = self.meta_storage[app]
self.r_server = redis.Redis(host=host, port=port, db=db or 0) self.r_server = redis.Redis(host=host, port=port, db=self.db)
def __call__(self, key, f, time_expire=300): def __call__(self, key, f, time_expire=300):
if time_expire == None: try:
time_expire = 10**10 if time_expire == None:
key = self.__keyFormat__(key) time_expire = 24*60*60
value = None newKey = self.__keyFormat__(key)
obj = self.r_server.get(key) value = None
if obj: obj = self.r_server.get(newKey)
if self.debug: ttl = self.r_server.ttl(newKey) or 0
self.r_server.incr('web2py_cache_statistics:hit_total') if ttl > time_expire:
value = pickle.loads(obj) obj = None
elif f is None: if obj:
if obj: self.r_server.delete(key) if self.debug:
else: self.r_server.incr('web2py_cache_statistics:hit_total')
if self.debug: value = pickle.loads(obj)
self.r_server.incr('web2py_cache_statistics:misses') elif f is None:
value = f() self.r_server.delete(newKey)
self.r_server.setex(key, pickle.dumps(value), time_expire) else:
return value if self.debug:
self.r_server.incr('web2py_cache_statistics:misses')
def increment(self, key, value=1, time_expire=300): value = f()
newKey = self.__keyFormat__(key) if time_expire == 0:
obj = self.r_server.get(newKey) time_expire = 1
if obj: self.r_server.setex(newKey, pickle.dumps(value), time_expire)
return self.r_server.incr(newKey, value)
else:
self.r_server.setex(newKey, value, time_expire)
return value return value
except ConnectionError:
return self.retry_call(key, f, time_expire)
def retry_call(self, key, f, time_expire):
self.RETRIES += 1
if self.RETRIES <= self.MAX_RETRIES:
logger.error("sleeping %s seconds before reconnecting" % (2 * self.RETRIES))
time.sleep(2 * self.RETRIES)
self.__init__(self.server, self.db, self.debug)
return self.__call__(key, f, time_expire)
else:
self.RETRIES = 0
raise ConnectionError , 'Redis instance is unavailable at %s' % (self.server)
def increment(self, key, value=1, time_expire=300):
try:
newKey = self.__keyFormat__(key)
obj = self.r_server.get(newKey)
if obj:
return self.r_server.incr(newKey, value)
else:
self.r_server.setex(newKey, value, time_expire)
return value
except ConnectionError:
return self.retry_increment(key, value, time_expire)
def retry_increment(self, key, value, time_expire):
self.RETRIES += 1
if self.RETRIES <= self.MAX_RETRIES:
logger.error("sleeping some seconds before reconnecting")
time.sleep(2 * self.RETRIES)
self.__init__(self.server, self.db, self.debug)
return self.increment(key, value, time_expire)
else:
self.RETRIES = 0
raise ConnectionError , 'Redis instance is unavailable at %s' % (self.server)
def clear(self, regex): def clear(self, regex):
""" """