class MemcachedAdapter(BaseAdapter): """ Exposes a cache store using Memcached. Exposes `pymemcache`'s exceptions. """ def __init__(self, host='localhost', port=11211, **kwargs): super().__init__() self.store = Client((host, port), **kwargs) def set(self, key, value, ttl): if ttl == -1: ttl = 0 return self.store.set(key, value, expire=ttl) def batch_set(self, keys, values, ttls): # There's two reasons to recode pymemcache.set_multi(): # - It returns a list of keys that failed to be inserted, and the base expects a boolean # - It only allows a unique ttl for all keys commands = [] ttls = [0 if ttl == -1 else ttl for ttl in ttls] for key, value, ttl in zip(keys, values, ttls): ttl = self.store._check_integer(ttl, 'expire') # pylint: disable=protected-access key = self.store.check_key(key) value, flags = self.store.serde.serialize(key, value) command = b'set ' + key command += b' ' + str(flags).encode(self.store.encoding) command += b' ' + ttl command += b' ' + str(len(value)).encode( self.store.encoding) + b'\r\n' command += value.encode(self.store.encoding) + b'\r\n' commands.append(command) results = self.store._misc_cmd(commands, 'set', False) # pylint: disable=protected-access for line in results: if line == b'NOT_STORED': return False return True def get(self, key): value = self.store.get(key) return value def batch_get(self, keys): key_to_value = self.store.get_multi(keys) values = [ key_to_value[key] if key in key_to_value else None for key in keys ] return values def delete(self, key): return self.store.delete(key, noreply=False) def batch_delete(self, keys): # Here as well, pymemcache.delete_multi() always returns True commands = [] for key in keys: key = self.store.check_key(key) command = b'delete ' + key + b'\r\n' commands.append(command) results = self.store._misc_cmd(commands, 'delete', False) # pylint: disable=protected-access for line in results: print(f"\"{line}\"") if line == b'NOT_FOUND': return False return True def exists(self, key): # Can't just cast to bool since we can store falsey values return self.store.get(key) is not None def flush(self): return self.store.flush_all(noreply=False) def ping(self): return bool(self.store.stats()) @property def connection_exceptions(self): return (MemcacheUnexpectedCloseError, MemcacheServerError, MemcacheUnknownError)
class OCPyMemcacheClient(object): """ OCPyMemcacheClient is the instrumented wrapper to provide traces and metrics to a pymemache.client.base.Client instance. It takes the exact arguments that a HashClient would take and underlyingly creates the client which it then wraps. The same usage pattern for the original client would apply here. """ __TRACKING_OPERATION = TrackingOperation() def __init__(self, server_addr, *args, **kwargs): self.__pymc = PyMemcacheClient(server_addr, *args, **kwargs) def add(self, key, value, *args, **kwargs): return self.__TRACKING_OPERATION.trace_and_record_stats( 'pymemcache.client.base.Client.add', self.__pymc.add, key, value, *args, **kwargs) def append(self, key, value, *args, **kwargs): return self.__TRACKING_OPERATION.trace_and_record_stats( 'pymemcache.client.base.Client.append', self.__pymc.append, key, value, *args, **kwargs) def cas(self, key, value, cas, *args, **kwargs): return self.__TRACKING_OPERATION.trace_and_record_stats( 'pymemcache.client.base.Client.cas', self.__pymc.cas, key, value, *args, **kwargs) def check_key(self, key): # Does not touch the remote end. return self.__pymc.check_key(key) def close(self): return self.__TRACKING_OPERATION.trace_and_record_stats( 'pymemcache.client.base.Client.close', self.__pymc.close) def decr(self, key, value, *args, **kwargs): return self.__TRACKING_OPERATION.trace_and_record_stats( 'pymemcache.client.base.Client.decr', self.__pymc.decr, key, value, *args, **kwargs) def delete(self, key, *args, **kwargs): return self.__TRACKING_OPERATION.trace_and_record_stats( 'pymemcache.client.base.Client.delete', self.__pymc.delete, key, *args, **kwargs) def delete_many(self, keys, *args, **kwargs): return self.__TRACKING_OPERATION.trace_and_record_stats( 'pymemcache.client.base.Client.delete_many', self.__pymc.delete_many, keys, *args, **kwargs) def delete_multi(self, keys, *args, **kwargs): return self.__TRACKING_OPERATION.trace_and_record_stats( 'pymemcache.client.base.Client.delete_multi', self.__pymc.delete_multi, keys, *args, **kwargs) def flush_all(self, *args, **kwargs): return self.__TRACKING_OPERATION.trace_and_record_stats( 'pymemcache.client.base.Client.flush_all', self.__pymc.flush_all, *args, **kwargs) def get(self, key, *args, **kwargs): return self.__TRACKING_OPERATION.trace_and_record_stats( 'pymemcache.client.base.Client.get', self.__pymc.get, key, *args, **kwargs) def get_many(self, keys, *args, **kwargs): return self.__TRACKING_OPERATION.trace_and_record_stats( 'pymemcache.client.base.Client.get_many', self.__pymc.get_many, key, *args, **kwargs) def get_multi(self, keys, *args, **kwargs): return self.__TRACKING_OPERATION.trace_and_record_stats( 'pymemcache.client.base.Client.get_multi', self.__pymc.get_multi, key, *args, **kwargs) def gets(self, keys, *args, **kwargs): return self.__TRACKING_OPERATION.trace_and_record_stats( 'pymemcache.client.base.Client.gets', self.__pymc.gets, keys, *args, **kwargs) def gets_many(self, keys, *args, **kwargs): return self.__TRACKING_OPERATION.trace_and_record_stats( 'pymemcache.client.base.Client.gets_many', self.__pymc.gets_many, keys, *args, **kwargs) def incr(self, key, value, *args, **kwargs): return self.__TRACKING_OPERATION.trace_and_record_stats( 'pymemcache.client.base.Client.incr', self.__pymc.incr, key, value, *args, **kwargs) def prepend(self, key, value, *args, **kwargs): return self.__TRACKING_OPERATION.trace_and_record_stats( 'pymemcache.client.base.Client.prepend', self.__pymc.prepend, key, value, *args, **kwargs) def quit(self, *args, **kwargs): return self.__TRACKING_OPERATION.trace_and_record_stats( 'pymemcache.client.base.Client.quit', self.__pymc.quit, *args, **kwargs) def replace(self, key, value, *args, **kwargs): return self.__TRACKING_OPERATION.trace_and_record_stats( 'pymemcache.client.base.Client.replace', self.__pymc.replace, key, value, *args, **kwargs) def set(self, key, value, *args, **kwargs): return self.__TRACKING_OPERATION.trace_and_record_stats( 'pymemcache.client.base.Client.set', self.__pymc.set, key, value, *args, **kwargs) def set_many(self, values, *args, **kwargs): return self.__TRACKING_OPERATION.trace_and_record_stats( 'pymemcache.client.base.Client.set_many', self.__pymc.set_many, values, *args, **kwargs) def set_multi(self, values, *args, **kwargs): return self.__TRACKING_OPERATION.trace_and_record_stats( 'pymemcache.client.base.Client.set_multi', self.__pymc.set_multi, values, *args, **kwargs) def stats(self, *args): return self.__TRACKING_OPERATION.trace_and_record_stats( 'pymemcache.client.base.Client.stats', self.__pymc.stats, *args) def touch(self, key, *args, **kwargs): return self.__TRACKING_OPERATION.trace_and_record_stats( 'pymemcache.client.base.Client.touch', self.__pymc.touch, *args, **kwargs) def version(self): return self.__TRACKING_OPERATION.trace_and_record_stats( 'pymemcache.client.base.Client.version', self.__pymc.version)