| Index: third_party/google-endpoints/dogpile/cache/backends/redis.py
|
| diff --git a/third_party/google-endpoints/dogpile/cache/backends/redis.py b/third_party/google-endpoints/dogpile/cache/backends/redis.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..d665320a7650ffe31380856e735aa3f854e97c06
|
| --- /dev/null
|
| +++ b/third_party/google-endpoints/dogpile/cache/backends/redis.py
|
| @@ -0,0 +1,183 @@
|
| +"""
|
| +Redis Backends
|
| +------------------
|
| +
|
| +Provides backends for talking to `Redis <http://redis.io>`_.
|
| +
|
| +"""
|
| +
|
| +from __future__ import absolute_import
|
| +from ..api import CacheBackend, NO_VALUE
|
| +from ...util.compat import pickle, u
|
| +
|
| +redis = None
|
| +
|
| +__all__ = 'RedisBackend',
|
| +
|
| +
|
| +class RedisBackend(CacheBackend):
|
| + """A `Redis <http://redis.io/>`_ backend, using the
|
| + `redis-py <http://pypi.python.org/pypi/redis/>`_ backend.
|
| +
|
| + Example configuration::
|
| +
|
| + from dogpile.cache import make_region
|
| +
|
| + region = make_region().configure(
|
| + 'dogpile.cache.redis',
|
| + arguments = {
|
| + 'host': 'localhost',
|
| + 'port': 6379,
|
| + 'db': 0,
|
| + 'redis_expiration_time': 60*60*2, # 2 hours
|
| + 'distributed_lock': True
|
| + }
|
| + )
|
| +
|
| + Arguments accepted in the arguments dictionary:
|
| +
|
| + :param url: string. If provided, will override separate host/port/db
|
| + params. The format is that accepted by ``StrictRedis.from_url()``.
|
| +
|
| + .. versionadded:: 0.4.1
|
| +
|
| + :param host: string, default is ``localhost``.
|
| +
|
| + :param password: string, default is no password.
|
| +
|
| + .. versionadded:: 0.4.1
|
| +
|
| + :param port: integer, default is ``6379``.
|
| +
|
| + :param db: integer, default is ``0``.
|
| +
|
| + :param redis_expiration_time: integer, number of seconds after setting
|
| + a value that Redis should expire it. This should be larger than dogpile's
|
| + cache expiration. By default no expiration is set.
|
| +
|
| + :param distributed_lock: boolean, when True, will use a
|
| + redis-lock as the dogpile lock.
|
| + Use this when multiple
|
| + processes will be talking to the same redis instance.
|
| + When left at False, dogpile will coordinate on a regular
|
| + threading mutex.
|
| +
|
| + :param lock_timeout: integer, number of seconds after acquiring a lock that
|
| + Redis should expire it. This argument is only valid when
|
| + ``distributed_lock`` is ``True``.
|
| +
|
| + .. versionadded:: 0.5.0
|
| +
|
| + :param socket_timeout: float, seconds for socket timeout.
|
| + Default is None (no timeout).
|
| +
|
| + .. versionadded:: 0.5.4
|
| +
|
| + :param lock_sleep: integer, number of seconds to sleep when failed to
|
| + acquire a lock. This argument is only valid when
|
| + ``distributed_lock`` is ``True``.
|
| +
|
| + .. versionadded:: 0.5.0
|
| +
|
| + :param connection_pool: ``redis.ConnectionPool`` object. If provided,
|
| + this object supersedes other connection arguments passed to the
|
| + ``redis.StrictRedis`` instance, including url and/or host as well as
|
| + socket_timeout, and will be passed to ``redis.StrictRedis`` as the
|
| + source of connectivity.
|
| +
|
| + .. versionadded:: 0.5.4
|
| +
|
| +
|
| + """
|
| +
|
| + def __init__(self, arguments):
|
| + arguments = arguments.copy()
|
| + self._imports()
|
| + self.url = arguments.pop('url', None)
|
| + self.host = arguments.pop('host', 'localhost')
|
| + self.password = arguments.pop('password', None)
|
| + self.port = arguments.pop('port', 6379)
|
| + self.db = arguments.pop('db', 0)
|
| + self.distributed_lock = arguments.get('distributed_lock', False)
|
| + self.socket_timeout = arguments.pop('socket_timeout', None)
|
| +
|
| + self.lock_timeout = arguments.get('lock_timeout', None)
|
| + self.lock_sleep = arguments.get('lock_sleep', 0.1)
|
| +
|
| + self.redis_expiration_time = arguments.pop('redis_expiration_time', 0)
|
| + self.connection_pool = arguments.get('connection_pool', None)
|
| + self.client = self._create_client()
|
| +
|
| + def _imports(self):
|
| + # defer imports until backend is used
|
| + global redis
|
| + import redis # noqa
|
| +
|
| + def _create_client(self):
|
| + if self.connection_pool is not None:
|
| + # the connection pool already has all other connection
|
| + # options present within, so here we disregard socket_timeout
|
| + # and others.
|
| + return redis.StrictRedis(connection_pool=self.connection_pool)
|
| +
|
| + args = {}
|
| + if self.socket_timeout:
|
| + args['socket_timeout'] = self.socket_timeout
|
| +
|
| + if self.url is not None:
|
| + args.update(url=self.url)
|
| + return redis.StrictRedis.from_url(**args)
|
| + else:
|
| + args.update(
|
| + host=self.host, password=self.password,
|
| + port=self.port, db=self.db
|
| + )
|
| + return redis.StrictRedis(**args)
|
| +
|
| + def get_mutex(self, key):
|
| + if self.distributed_lock:
|
| + return self.client.lock(u('_lock{0}').format(key),
|
| + self.lock_timeout, self.lock_sleep)
|
| + else:
|
| + return None
|
| +
|
| + def get(self, key):
|
| + value = self.client.get(key)
|
| + if value is None:
|
| + return NO_VALUE
|
| + return pickle.loads(value)
|
| +
|
| + def get_multi(self, keys):
|
| + if not keys:
|
| + return []
|
| + values = self.client.mget(keys)
|
| + return [
|
| + pickle.loads(v) if v is not None else NO_VALUE
|
| + for v in values]
|
| +
|
| + def set(self, key, value):
|
| + if self.redis_expiration_time:
|
| + self.client.setex(key, self.redis_expiration_time,
|
| + pickle.dumps(value, pickle.HIGHEST_PROTOCOL))
|
| + else:
|
| + self.client.set(key, pickle.dumps(value, pickle.HIGHEST_PROTOCOL))
|
| +
|
| + def set_multi(self, mapping):
|
| + mapping = dict(
|
| + (k, pickle.dumps(v, pickle.HIGHEST_PROTOCOL))
|
| + for k, v in mapping.items()
|
| + )
|
| +
|
| + if not self.redis_expiration_time:
|
| + self.client.mset(mapping)
|
| + else:
|
| + pipe = self.client.pipeline()
|
| + for key, value in mapping.items():
|
| + pipe.setex(key, self.redis_expiration_time, value)
|
| + pipe.execute()
|
| +
|
| + def delete(self, key):
|
| + self.client.delete(key)
|
| +
|
| + def delete_multi(self, keys):
|
| + self.client.delete(*keys)
|
|
|