Source code for wheezy.caching.pylibmc

""" ``pylibmc`` module.
"""

from wheezy.caching.encoding import encode_keys, string_encode

try:
    from pylibmc import Client, NotFound

    def client_factory(*args, **kwargs):
        """Client factory for pylibmc."""
        kwargs.setdefault("binary", True)
        behaviors = kwargs.setdefault("behaviors", {})
        behaviors.setdefault("tcp_nodelay", True)
        behaviors.setdefault("ketama", True)
        return Client(*args, **kwargs)


except ImportError:  # pragma: nocover
    import warnings

    warnings.warn("No module named 'pylibmc'", stacklevel=2)


[docs]class MemcachedClient(object): """A wrapper around pylibmc Client in order to adapt cache contract.""" def __init__(self, pool, key_encode=None): assert hasattr(pool, "acquire") assert hasattr(pool, "get_back") self.pool = pool self.key_encode = key_encode or string_encode
[docs] def set(self, key, value, time=0, namespace=None): """Sets a key's value, regardless of previous contents in cache. """ key = self.key_encode(key) try: client = self.pool.acquire() return client.set(key, value, time) finally: self.pool.get_back(client)
[docs] def set_multi(self, mapping, time=0, namespace=None): """Set multiple keys' values at once.""" key_encode = self.key_encode keys, mapping = encode_keys(mapping, key_encode) try: client = self.pool.acquire() failed = client.set_multi(mapping, time) finally: self.pool.get_back(client) return failed and [keys[key] for key in failed] or failed
[docs] def add(self, key, value, time=0, namespace=None): """Sets a key's value, if and only if the item is not already. """ key = self.key_encode(key) try: client = self.pool.acquire() return client.add(key, value, time) finally: self.pool.get_back(client)
[docs] def add_multi(self, mapping, time=0, namespace=None): """Adds multiple values at once, with no effect for keys already in cache. """ key_encode = self.key_encode keys, mapping = encode_keys(mapping, key_encode) try: client = self.pool.acquire() failed = client.add_multi(mapping, time) finally: self.pool.get_back(client) return failed and [keys[key] for key in failed] or failed
[docs] def replace(self, key, value, time=0, namespace=None): """Replaces a key's value, failing if item isn't already.""" key = self.key_encode(key) try: try: client = self.pool.acquire() return client.replace(key, value, time) except NotFound: return False finally: self.pool.get_back(client)
[docs] def replace_multi(self, mapping, time=0, namespace=None): """Replaces multiple values at once, with no effect for keys not in cache. """ key_encode = self.key_encode failed = [] mapping = [(key, key_encode(key), mapping[key]) for key in mapping] try: client = self.pool.acquire() for key, key_encoded, value in mapping: try: client.replace(key_encoded, value, time) except NotFound: failed.append(key) finally: self.pool.get_back(client) return failed
[docs] def get(self, key, namespace=None): """Looks up a single key.""" key = self.key_encode(key) try: client = self.pool.acquire() return client.get(key) finally: self.pool.get_back(client)
[docs] def get_multi(self, keys, namespace=None): """Looks up multiple keys from cache in one operation. This is the recommended way to do bulk loads. """ key_encode = self.key_encode encoded_keys = list(map(key_encode, keys)) try: client = self.pool.acquire() mapping = client.get_multi(encoded_keys) finally: self.pool.get_back(client) if mapping: key_mapping = dict(zip(encoded_keys, keys)) return dict([(key_mapping[key], mapping[key]) for key in mapping]) return mapping
[docs] def delete(self, key, seconds=0, namespace=None): """Deletes a key from cache.""" key = self.key_encode(key) try: client = self.pool.acquire() return client.delete(key) finally: self.pool.get_back(client)
[docs] def delete_multi(self, keys, seconds=0, namespace=None): """Delete multiple keys at once.""" key_encode = self.key_encode keys = map(key_encode, keys) try: client = self.pool.acquire() return client.delete_multi(keys) finally: self.pool.get_back(client)
[docs] def incr(self, key, delta=1, namespace=None, initial_value=None): """Atomically increments a key's value. The value, if too large, will wrap around. If the key does not yet exist in the cache and you specify an initial_value, the key's value will be set to this initial value and then incremented. If the key does not exist and no initial_value is specified, the key's value will not be set. """ key = self.key_encode(key) try: client = self.pool.acquire() try: return client.incr(key, delta) except NotFound: if initial_value is None: return None client.add(key, initial_value) return client.incr(key, delta) finally: self.pool.get_back(client)
[docs] def decr(self, key, delta=1, namespace=None, initial_value=None): """Atomically decrements a key's value. The value, if too large, will wrap around. If the key does not yet exist in the cache and you specify an initial_value, the key's value will be set to this initial value and then decremented. If the key does not exist and no initial_value is specified, the key's value will not be set. """ key = self.key_encode(key) try: client = self.pool.acquire() try: return client.decr(key, delta) except NotFound: if initial_value is None: return None client.add(key, initial_value) return client.decr(key, delta) finally: self.pool.get_back(client)
[docs] def flush_all(self): """Deletes everything in cache.""" try: client = self.pool.acquire() client.flush_all() finally: self.pool.get_back(client) return True