def __init__(self, address, protocol = "text", codec = "default"): self._address = address self._stream = None self._read_queue = DeferredQueue() self._write_queue = DeferredQueue() self._protocol = MemcacheProtocol.create(protocol) self._protocol.set_codec(MemcacheCodec.create(codec))
class MemcacheConnection(object): log = logging.getLogger("MemcacheConnection") _read_timeout = 2 _write_timeout = 2 def __init__(self, address, protocol = "text", codec = "default"): self._address = address self._stream = None self._read_queue = DeferredQueue() self._write_queue = DeferredQueue() self._protocol = MemcacheProtocol.create(protocol) self._protocol.set_codec(MemcacheCodec.create(codec)) def connect(self): self.log.log(logging.TRACE, "Connecting to Memcache %s", self._address) self._stream = BufferedStream(socket.create_connection(self._address)) def disconnect(self): if self._stream is None: return try: self._stream.close() except: pass self._stream = None def is_connected(self): return self._stream is not None def flush(self): self._stream.flush() def _write_command(self, cmd, args, flush = True): with self._stream.get_writer() as writer: getattr(self._protocol, 'write_' + cmd)(writer, *args) if flush: writer.flush() def _read_result(self, cmd): with self._stream.get_reader() as reader: return getattr(self._protocol, 'read_' + cmd)(reader) def _defer_command(self, cmd, args, result_channel, error_value = None): def _read_result(): timeout = Timeout(self._read_timeout, Timeout) timeout.start() try: result = self._read_result(cmd) result_channel.put(result) except Timeout: raise except: self.log.exception("read error in defer_command") result_channel.put((MemcacheResult.ERROR, error_value)) self.log.warn("Error communicating with Memcache %s, disconnecting", self._address) self.disconnect() finally: timeout.cancel() def _write_command(): timeout = Timeout(self._write_timeout, Timeout) timeout.start() try: if not self.is_connected(): self.connect() self._write_command(cmd, args, True) self._read_queue.defer(_read_result) except Timeout: raise except: result_channel.put((MemcacheResult.ERROR, error_value)) self.log.warn("Error communicating with Memcache %s, disconnecting", self._address) self.disconnect() finally: timeout.cancel() self._write_queue.defer(_write_command) def _do_command(self, cmd, args, error_value = None): result_channel = ResultChannel() self._defer_command(cmd, args, result_channel, error_value) try: return result_channel.get() except TimeoutError: return MemcacheResult.TIMEOUT, error_value def close(self): if self.is_connected(): self._stream.close() self._stream = None def delete(self, key, expiration = 0): return self._do_command("delete", (key, expiration))[0] def set(self, key, data, expiration = 0, flags = 0): return self._do_command("set", (key, data, expiration, flags))[0] def __setitem__(self, key, data): self.set(key, data) def add(self, key, data, expiration = 0, flags = 0): return self._do_command("add", (key, data, expiration, flags))[0] def replace(self, key, data, expiration = 0, flags = 0): return self._do_command("replace", (key, data, expiration, flags))[0] def append(self, key, data, expiration = 0, flags = 0): return self._do_command("append", (key, data, expiration, flags))[0] def prepend(self, key, data, expiration = 0, flags = 0): return self._do_command("prepend", (key, data, expiration, flags))[0] def cas(self, key, data, cas_unique, expiration = 0, flags = 0): return self._do_command("cas", (key, data, expiration, flags, cas_unique))[0] def incr(self, key, delta = 1): return self._do_command("incr", (key, delta)) def decr(self, key, delta = 1): return self._do_command("decr", (key, delta)) def get(self, key, default = None): _, values = self._do_command("get", ([key], ), {}) return values.get(key, default) def __getitem__(self, key): return self.get(key) def getr(self, key, default = None): result, values = self._do_command("get", ([key], ), {}) return result, values.get(key, default) def gets(self, key, default = None): result, values = self._do_command("gets", ([key], ), {}) value, cas_unique = values.get(key, (default, None)) return result, value, cas_unique def get_multi(self, keys): return self._do_command("get", (keys, )) def gets_multi(self, keys): return self._do_command("gets", (keys, )) def version(self): return self._do_command("version", ()) def stats(self): return self._do_command("stats", ())