def _init(self, server, params): super(CacheClass, self).__init__(params) self._server = server self._params = params unix_socket_path = None if ':' in self.server: host, port = self.server.rsplit(':', 1) try: port = int(port) except (ValueError, TypeError): raise Exception("port value must be an integer") else: host, port = None, None unix_socket_path = self.server kwargs = { 'db': self.db, 'password': self.password, 'host': host, 'port': port, 'unix_socket_path': unix_socket_path, } connection_pool = pool.get_connection_pool( parser_class=self.parser_class, **kwargs ) self._client = Redis( connection_pool=connection_pool, **kwargs )
def from_url(url, db=None, **kwargs): """Returns an active Redis client generated from the given database URL. Will attempt to extract the database id from the path url fragment, if none is provided. """ return Redis.from_url(url, db, **kwargs)
class CacheClass(BaseCache): def __init__(self, server, params): """ Connect to Redis, and set up cache backend. """ self._init(server, params) def _init(self, server, params): super(CacheClass, self).__init__(params) self._server = server self._params = params unix_socket_path = None if ':' in self.server: host, port = self.server.rsplit(':', 1) try: port = int(port) except (ValueError, TypeError): raise Exception("port value must be an integer") else: host, port = None, None unix_socket_path = self.server kwargs = { 'db': self.db, 'password': self.password, 'host': host, 'port': port, 'unix_socket_path': unix_socket_path, } connection_pool = pool.get_connection_pool( parser_class=self.parser_class, **kwargs ) self._client = Redis( connection_pool=connection_pool, **kwargs ) @property def server(self): return self._server or "127.0.0.1:6379" @property def params(self): return self._params or {} @property def options(self): return self.params.get('OPTIONS', {}) @property def db(self): _db = self.params.get('db', self.options.get('DB', 1)) try: _db = int(_db) except (ValueError, TypeError): raise Exception("db value must be an integer") return _db @property def password(self): return self.params.get('password', self.options.get('PASSWORD', None)) @property def parser_class(self): cls = self.options.get('PARSER_CLASS', None) if cls is None: return DefaultParser mod_path, cls_name = cls.rsplit('.', 1) try: mod = import_module(mod_path) parser_class = getattr(mod, cls_name) except (AttributeError, ImportError): raise Exception("Could not find parser class '%s'" % parser_class) return parser_class def __getstate__(self): return {'params': self._params, 'server': self._server} def __setstate__(self, state): self._init(**state) def make_key(self, key, version=None): """ Returns the utf-8 encoded bytestring of the given key as a CacheKey instance to be able to check if it was "made" before. """ if not isinstance(key, CacheKey): key = CacheKey(key) return key def add(self, key, value, timeout=None, version=None): """ Add a value to the cache, failing if the key already exists. Returns ``True`` if the object was added, ``False`` if not. """ return self.set(key, value, timeout, _add_only=True) def get(self, key, default=None, version=None): """ Retrieve a value from the cache. Returns unpickled value if key is found, the default if not. """ key = self.make_key(key, version=version) value = self._client.get(key) if value is None: return default try: result = int(value) except (ValueError, TypeError): result = self.unpickle(value) return result def _set(self, key, value, timeout, client, _add_only=False): if timeout == 0: if _add_only: return client.setnx(key, value) return client.set(key, value) elif timeout > 0: if _add_only: added = client.setnx(key, value) if added: client.expire(key, timeout) return added return client.setex(key, value, timeout) else: return False def set(self, key, value, timeout=None, version=None, client=None, _add_only=False): """ Persist a value to the cache, and set an optional expiration time. """ if not client: client = self._client key = self.make_key(key, version=version) if timeout is None: timeout = self.default_timeout try: value = float(value) # If you lose precision from the typecast to str, then pickle value if int(value) != value: raise TypeError except (ValueError, TypeError): result = self._set(key, pickle.dumps(value), int(timeout), client, _add_only) else: result = self._set(key, int(value), int(timeout), client, _add_only) # result is a boolean return result def delete(self, key, version=None): """ Remove a key from the cache. """ self._client.delete(self.make_key(key, version=version)) def delete_many(self, keys, version=None): """ Remove multiple keys at once. """ if keys: keys = map(lambda key: self.make_key(key, version=version), keys) self._client.delete(*keys) def clear(self): """ Flush all cache keys. """ # TODO : potential data loss here, should we only delete keys based on the correct version ? self._client.flushdb() def unpickle(self, value): """ Unpickles the given value. """ value = smart_str(value) return pickle.loads(value) def get_many(self, keys, version=None): """ Retrieve many keys. """ if not keys: return {} recovered_data = dict() new_keys = map(lambda key: self.make_key(key, version=version), keys) map_keys = dict(zip(new_keys, keys)) results = self._client.mget(new_keys) for key, value in zip(new_keys, results): if value is None: continue try: value = int(value) except (ValueError, TypeError): value = self.unpickle(value) if isinstance(value, basestring): value = smart_unicode(value) recovered_data[map_keys[key]] = value return recovered_data def set_many(self, data, timeout=None, version=None): """ Set a bunch of values in the cache at once from a dict of key/value pairs. This is much more efficient than calling set() multiple times. If timeout is given, that timeout will be used for the key; otherwise the default cache timeout will be used. """ pipeline = self._client.pipeline() for key, value in data.iteritems(): self.set(key, value, timeout, version=version, client=pipeline) pipeline.execute() def set_json(self, key, json, **kwargs): return self._client.hmset(key, json) def get_json(self, key): return self._client.hgetall(key) def exists(self, key): return self._client.exists(key) def expire(self, key, ttl): return self._client.expire(key, ttl) def incr(self, key, delta=1, version=None): """ Add delta to value in the cache. If the key does not exist, raise a ValueError exception. """ key = self.make_key(key, version=version) exists = self._client.exists(key) if not exists: raise ValueError("Key '%s' not found" % key) try: value = self._client.incr(key, delta) except ResponseError: value = self.get(key) + 1 self.set(key, value) return value