Index: third_party/twisted_8_1/twisted/protocols/memcache.py |
diff --git a/third_party/twisted_8_1/twisted/protocols/memcache.py b/third_party/twisted_8_1/twisted/protocols/memcache.py |
deleted file mode 100644 |
index 4862cd5a5d16358a178fb0b69356490b6478869a..0000000000000000000000000000000000000000 |
--- a/third_party/twisted_8_1/twisted/protocols/memcache.py |
+++ /dev/null |
@@ -1,657 +0,0 @@ |
-# -*- test-case-name: twisted.test.test_memcache -*- |
-# Copyright (c) 2007 Twisted Matrix Laboratories. |
-# See LICENSE for details. |
- |
-""" |
-Memcache client protocol. Memcached is a caching server, storing data in the |
-form of pairs key/value, and memcache is the protocol to talk with it. |
- |
-To connect to a server, create a factory for L{MemCacheProtocol}:: |
- |
- from twisted.internet import reactor, protocol |
- from twisted.protocols.memcache import MemCacheProtocol, DEFAULT_PORT |
- d = protocol.ClientCreator(reactor, MemCacheProtocol |
- ).connectTCP("localhost", DEFAULT_PORT) |
- def doSomething(proto): |
- # Here you call the memcache operations |
- return proto.set("mykey", "a lot of data") |
- d.addCallback(doSomething) |
- reactor.run() |
- |
-All the operations of the memcache protocol are present, but |
-L{MemCacheProtocol.set} and L{MemCacheProtocol.get} are the more important. |
- |
-See U{http://code.sixapart.com/svn/memcached/trunk/server/doc/protocol.txt} for |
-more information about the protocol. |
-""" |
- |
-try: |
- from collections import deque |
-except ImportError: |
- class deque(list): |
- def popleft(self): |
- return self.pop(0) |
- |
- |
-from twisted.protocols.basic import LineReceiver |
-from twisted.protocols.policies import TimeoutMixin |
-from twisted.internet.defer import Deferred, fail, TimeoutError |
-from twisted.python import log |
- |
- |
- |
-DEFAULT_PORT = 11211 |
- |
- |
- |
-class NoSuchCommand(Exception): |
- """ |
- Exception raised when a non existent command is called. |
- """ |
- |
- |
- |
-class ClientError(Exception): |
- """ |
- Error caused by an invalid client call. |
- """ |
- |
- |
- |
-class ServerError(Exception): |
- """ |
- Problem happening on the server. |
- """ |
- |
- |
- |
-class Command(object): |
- """ |
- Wrap a client action into an object, that holds the values used in the |
- protocol. |
- |
- @ivar _deferred: the L{Deferred} object that will be fired when the result |
- arrives. |
- @type _deferred: L{Deferred} |
- |
- @ivar command: name of the command sent to the server. |
- @type command: C{str} |
- """ |
- |
- def __init__(self, command, **kwargs): |
- """ |
- Create a command. |
- |
- @param command: the name of the command. |
- @type command: C{str} |
- |
- @param kwargs: this values will be stored as attributes of the object |
- for future use |
- """ |
- self.command = command |
- self._deferred = Deferred() |
- for k, v in kwargs.items(): |
- setattr(self, k, v) |
- |
- |
- def success(self, value): |
- """ |
- Shortcut method to fire the underlying deferred. |
- """ |
- self._deferred.callback(value) |
- |
- |
- def fail(self, error): |
- """ |
- Make the underlying deferred fails. |
- """ |
- self._deferred.errback(error) |
- |
- |
- |
-class MemCacheProtocol(LineReceiver, TimeoutMixin): |
- """ |
- MemCache protocol: connect to a memcached server to store/retrieve values. |
- |
- @ivar persistentTimeOut: the timeout period used to wait for a response. |
- @type persistentTimeOut: C{int} |
- |
- @ivar _current: current list of requests waiting for an answer from the |
- server. |
- @type _current: C{deque} of L{Command} |
- |
- @ivar _lenExpected: amount of data expected in raw mode, when reading for |
- a value. |
- @type _lenExpected: C{int} |
- |
- @ivar _getBuffer: current buffer of data, used to store temporary data |
- when reading in raw mode. |
- @type _getBuffer: C{list} |
- |
- @ivar _bufferLength: the total amount of bytes in C{_getBuffer}. |
- @type _bufferLength: C{int} |
- """ |
- MAX_KEY_LENGTH = 250 |
- |
- def __init__(self, timeOut=60): |
- """ |
- Create the protocol. |
- |
- @param timeOut: the timeout to wait before detecting that the |
- connection is dead and close it. It's expressed in seconds. |
- @type timeOut: C{int} |
- """ |
- self._current = deque() |
- self._lenExpected = None |
- self._getBuffer = None |
- self._bufferLength = None |
- self.persistentTimeOut = self.timeOut = timeOut |
- |
- |
- def timeoutConnection(self): |
- """ |
- Close the connection in case of timeout. |
- """ |
- for cmd in self._current: |
- cmd.fail(TimeoutError("Connection timeout")) |
- self.transport.loseConnection() |
- |
- |
- def sendLine(self, line): |
- """ |
- Override sendLine to add a timeout to response. |
- """ |
- if not self._current: |
- self.setTimeout(self.persistentTimeOut) |
- LineReceiver.sendLine(self, line) |
- |
- |
- def rawDataReceived(self, data): |
- """ |
- Collect data for a get. |
- """ |
- self.resetTimeout() |
- self._getBuffer.append(data) |
- self._bufferLength += len(data) |
- if self._bufferLength >= self._lenExpected + 2: |
- data = "".join(self._getBuffer) |
- buf = data[:self._lenExpected] |
- rem = data[self._lenExpected + 2:] |
- val = buf |
- self._lenExpected = None |
- self._getBuffer = None |
- self._bufferLength = None |
- cmd = self._current[0] |
- cmd.value = val |
- self.setLineMode(rem) |
- |
- |
- def cmd_STORED(self): |
- """ |
- Manage a success response to a set operation. |
- """ |
- self._current.popleft().success(True) |
- |
- |
- def cmd_NOT_STORED(self): |
- """ |
- Manage a specific 'not stored' response to a set operation: this is not |
- an error, but some condition wasn't met. |
- """ |
- self._current.popleft().success(False) |
- |
- |
- def cmd_END(self): |
- """ |
- This the end token to a get or a stat operation. |
- """ |
- cmd = self._current.popleft() |
- if cmd.command == "get": |
- cmd.success((cmd.flags, cmd.value)) |
- elif cmd.command == "gets": |
- cmd.success((cmd.flags, cmd.cas, cmd.value)) |
- elif cmd.command == "stats": |
- cmd.success(cmd.values) |
- |
- |
- def cmd_NOT_FOUND(self): |
- """ |
- Manage error response for incr/decr/delete. |
- """ |
- self._current.popleft().success(False) |
- |
- |
- def cmd_VALUE(self, line): |
- """ |
- Prepare the reading a value after a get. |
- """ |
- cmd = self._current[0] |
- if cmd.command == "get": |
- key, flags, length = line.split() |
- cas = "" |
- else: |
- key, flags, length, cas = line.split() |
- self._lenExpected = int(length) |
- self._getBuffer = [] |
- self._bufferLength = 0 |
- if cmd.key != key: |
- raise RuntimeError("Unexpected commands answer.") |
- cmd.flags = int(flags) |
- cmd.length = self._lenExpected |
- cmd.cas = cas |
- self.setRawMode() |
- |
- |
- def cmd_STAT(self, line): |
- """ |
- Reception of one stat line. |
- """ |
- cmd = self._current[0] |
- key, val = line.split(" ", 1) |
- cmd.values[key] = val |
- |
- |
- def cmd_VERSION(self, versionData): |
- """ |
- Read version token. |
- """ |
- self._current.popleft().success(versionData) |
- |
- |
- def cmd_ERROR(self): |
- """ |
- An non-existent command has been sent. |
- """ |
- log.err("Non-existent command sent.") |
- cmd = self._current.popleft() |
- cmd.fail(NoSuchCommand()) |
- |
- |
- def cmd_CLIENT_ERROR(self, errText): |
- """ |
- An invalid input as been sent. |
- """ |
- log.err("Invalid input: %s" % (errText,)) |
- cmd = self._current.popleft() |
- cmd.fail(ClientError(errText)) |
- |
- |
- def cmd_SERVER_ERROR(self, errText): |
- """ |
- An error has happened server-side. |
- """ |
- log.err("Server error: %s" % (errText,)) |
- cmd = self._current.popleft() |
- cmd.fail(ServerError(errText)) |
- |
- |
- def cmd_DELETED(self): |
- """ |
- A delete command has completed successfully. |
- """ |
- self._current.popleft().success(True) |
- |
- |
- def cmd_OK(self): |
- """ |
- The last command has been completed. |
- """ |
- self._current.popleft().success(True) |
- |
- |
- def cmd_EXISTS(self): |
- """ |
- A C{checkAndSet} update has failed. |
- """ |
- self._current.popleft().success(False) |
- |
- |
- def lineReceived(self, line): |
- """ |
- Receive line commands from the server. |
- """ |
- self.resetTimeout() |
- token = line.split(" ", 1)[0] |
- # First manage standard commands without space |
- cmd = getattr(self, "cmd_%s" % (token,), None) |
- if cmd is not None: |
- args = line.split(" ", 1)[1:] |
- if args: |
- cmd(args[0]) |
- else: |
- cmd() |
- else: |
- # Then manage commands with space in it |
- line = line.replace(" ", "_") |
- cmd = getattr(self, "cmd_%s" % (line,), None) |
- if cmd is not None: |
- cmd() |
- else: |
- # Increment/Decrement response |
- cmd = self._current.popleft() |
- val = int(line) |
- cmd.success(val) |
- if not self._current: |
- # No pending request, remove timeout |
- self.setTimeout(None) |
- |
- |
- def increment(self, key, val=1): |
- """ |
- Increment the value of C{key} by given value (default to 1). |
- C{key} must be consistent with an int. Return the new value. |
- |
- @param key: the key to modify. |
- @type key: C{str} |
- |
- @param val: the value to increment. |
- @type val: C{int} |
- |
- @return: a deferred with will be called back with the new value |
- associated with the key (after the increment). |
- @rtype: L{Deferred} |
- """ |
- return self._incrdecr("incr", key, val) |
- |
- |
- def decrement(self, key, val=1): |
- """ |
- Decrement the value of C{key} by given value (default to 1). |
- C{key} must be consistent with an int. Return the new value, coerced to |
- 0 if negative. |
- |
- @param key: the key to modify. |
- @type key: C{str} |
- |
- @param val: the value to decrement. |
- @type val: C{int} |
- |
- @return: a deferred with will be called back with the new value |
- associated with the key (after the decrement). |
- @rtype: L{Deferred} |
- """ |
- return self._incrdecr("decr", key, val) |
- |
- |
- def _incrdecr(self, cmd, key, val): |
- """ |
- Internal wrapper for incr/decr. |
- """ |
- if not isinstance(key, str): |
- return fail(ClientError( |
- "Invalid type for key: %s, expecting a string" % (type(key),))) |
- if len(key) > self.MAX_KEY_LENGTH: |
- return fail(ClientError("Key too long")) |
- fullcmd = "%s %s %d" % (cmd, key, int(val)) |
- self.sendLine(fullcmd) |
- cmdObj = Command(cmd, key=key) |
- self._current.append(cmdObj) |
- return cmdObj._deferred |
- |
- |
- def replace(self, key, val, flags=0, expireTime=0): |
- """ |
- Replace the given C{key}. It must already exist in the server. |
- |
- @param key: the key to replace. |
- @type key: C{str} |
- |
- @param val: the new value associated with the key. |
- @type val: C{str} |
- |
- @param flags: the flags to store with the key. |
- @type flags: C{int} |
- |
- @param expireTime: if different from 0, the relative time in seconds |
- when the key will be deleted from the store. |
- @type expireTime: C{int} |
- |
- @return: a deferred that will fire with C{True} if the operation has |
- succeeded, and C{False} with the key didn't previously exist. |
- @rtype: L{Deferred} |
- """ |
- return self._set("replace", key, val, flags, expireTime, "") |
- |
- |
- def add(self, key, val, flags=0, expireTime=0): |
- """ |
- Add the given C{key}. It must not exist in the server. |
- |
- @param key: the key to add. |
- @type key: C{str} |
- |
- @param val: the value associated with the key. |
- @type val: C{str} |
- |
- @param flags: the flags to store with the key. |
- @type flags: C{int} |
- |
- @param expireTime: if different from 0, the relative time in seconds |
- when the key will be deleted from the store. |
- @type expireTime: C{int} |
- |
- @return: a deferred that will fire with C{True} if the operation has |
- succeeded, and C{False} with the key already exists. |
- @rtype: L{Deferred} |
- """ |
- return self._set("add", key, val, flags, expireTime, "") |
- |
- |
- def set(self, key, val, flags=0, expireTime=0): |
- """ |
- Set the given C{key}. |
- |
- @param key: the key to set. |
- @type key: C{str} |
- |
- @param val: the value associated with the key. |
- @type val: C{str} |
- |
- @param flags: the flags to store with the key. |
- @type flags: C{int} |
- |
- @param expireTime: if different from 0, the relative time in seconds |
- when the key will be deleted from the store. |
- @type expireTime: C{int} |
- |
- @return: a deferred that will fire with C{True} if the operation has |
- succeeded. |
- @rtype: L{Deferred} |
- """ |
- return self._set("set", key, val, flags, expireTime, "") |
- |
- |
- def checkAndSet(self, key, val, cas, flags=0, expireTime=0): |
- """ |
- Change the content of C{key} only if the C{cas} value matches the |
- current one associated with the key. Use this to store a value which |
- hasn't been modified since last time you fetched it. |
- |
- @param key: The key to set. |
- @type key: C{str} |
- |
- @param val: The value associated with the key. |
- @type val: C{str} |
- |
- @param cas: Unique 64-bit value returned by previous call of C{get}. |
- @type cas: C{str} |
- |
- @param flags: The flags to store with the key. |
- @type flags: C{int} |
- |
- @param expireTime: If different from 0, the relative time in seconds |
- when the key will be deleted from the store. |
- @type expireTime: C{int} |
- |
- @return: A deferred that will fire with C{True} if the operation has |
- succeeded, C{False} otherwise. |
- @rtype: L{Deferred} |
- """ |
- return self._set("cas", key, val, flags, expireTime, cas) |
- |
- |
- def _set(self, cmd, key, val, flags, expireTime, cas): |
- """ |
- Internal wrapper for setting values. |
- """ |
- if not isinstance(key, str): |
- return fail(ClientError( |
- "Invalid type for key: %s, expecting a string" % (type(key),))) |
- if len(key) > self.MAX_KEY_LENGTH: |
- return fail(ClientError("Key too long")) |
- if not isinstance(val, str): |
- return fail(ClientError( |
- "Invalid type for value: %s, expecting a string" % |
- (type(val),))) |
- if cas: |
- cas = " " + cas |
- length = len(val) |
- fullcmd = "%s %s %d %d %d%s" % ( |
- cmd, key, flags, expireTime, length, cas) |
- self.sendLine(fullcmd) |
- self.sendLine(val) |
- cmdObj = Command(cmd, key=key, flags=flags, length=length) |
- self._current.append(cmdObj) |
- return cmdObj._deferred |
- |
- |
- def append(self, key, val): |
- """ |
- Append given data to the value of an existing key. |
- |
- @param key: The key to modify. |
- @type key: C{str} |
- |
- @param val: The value to append to the current value associated with |
- the key. |
- @type val: C{str} |
- |
- @return: A deferred that will fire with C{True} if the operation has |
- succeeded, C{False} otherwise. |
- @rtype: L{Deferred} |
- """ |
- # Even if flags and expTime values are ignored, we have to pass them |
- return self._set("append", key, val, 0, 0, "") |
- |
- |
- def prepend(self, key, val): |
- """ |
- Prepend given data to the value of an existing key. |
- |
- @param key: The key to modify. |
- @type key: C{str} |
- |
- @param val: The value to prepend to the current value associated with |
- the key. |
- @type val: C{str} |
- |
- @return: A deferred that will fire with C{True} if the operation has |
- succeeded, C{False} otherwise. |
- @rtype: L{Deferred} |
- """ |
- # Even if flags and expTime values are ignored, we have to pass them |
- return self._set("prepend", key, val, 0, 0, "") |
- |
- |
- def get(self, key, withIdentifier=False): |
- """ |
- Get the given C{key}. It doesn't support multiple keys. If |
- C{withIdentifier} is set to C{True}, the command issued is a C{gets}, |
- that will return the current identifier associated with the value. This |
- identifier has to be used when issuing C{checkAndSet} update later, |
- using the corresponding method. |
- |
- @param key: The key to retrieve. |
- @type key: C{str} |
- |
- @param withIdentifier: If set to C{True}, retrieve the current |
- identifier along with the value and the flags. |
- @type withIdentifier: C{bool} |
- |
- @return: A deferred that will fire with the tuple (flags, value) if |
- C{withIdentifier} is C{False}, or (flags, cas identifier, value) |
- if C{True}. |
- @rtype: L{Deferred} |
- """ |
- if not isinstance(key, str): |
- return fail(ClientError( |
- "Invalid type for key: %s, expecting a string" % (type(key),))) |
- if len(key) > self.MAX_KEY_LENGTH: |
- return fail(ClientError("Key too long")) |
- if withIdentifier: |
- cmd = "gets" |
- else: |
- cmd = "get" |
- fullcmd = "%s %s" % (cmd, key) |
- self.sendLine(fullcmd) |
- cmdObj = Command(cmd, key=key, value=None, flags=0, cas="") |
- self._current.append(cmdObj) |
- return cmdObj._deferred |
- |
- |
- def stats(self): |
- """ |
- Get some stats from the server. It will be available as a dict. |
- |
- @return: a deferred that will fire with a C{dict} of the available |
- statistics. |
- @rtype: L{Deferred} |
- """ |
- self.sendLine("stats") |
- cmdObj = Command("stats", values={}) |
- self._current.append(cmdObj) |
- return cmdObj._deferred |
- |
- |
- def version(self): |
- """ |
- Get the version of the server. |
- |
- @return: a deferred that will fire with the string value of the |
- version. |
- @rtype: L{Deferred} |
- """ |
- self.sendLine("version") |
- cmdObj = Command("version") |
- self._current.append(cmdObj) |
- return cmdObj._deferred |
- |
- |
- def delete(self, key): |
- """ |
- Delete an existing C{key}. |
- |
- @param key: the key to delete. |
- @type key: C{str} |
- |
- @return: a deferred that will be called back with C{True} if the key |
- was successfully deleted, or C{False} if not. |
- @rtype: L{Deferred} |
- """ |
- if not isinstance(key, str): |
- return fail(ClientError( |
- "Invalid type for key: %s, expecting a string" % (type(key),))) |
- self.sendLine("delete %s" % key) |
- cmdObj = Command("delete", key=key) |
- self._current.append(cmdObj) |
- return cmdObj._deferred |
- |
- |
- def flushAll(self): |
- """ |
- Flush all cached values. |
- |
- @return: a deferred that will be called back with C{True} when the |
- operation has succeeded. |
- @rtype: L{Deferred} |
- """ |
- self.sendLine("flush_all") |
- cmdObj = Command("flush_all") |
- self._current.append(cmdObj) |
- return cmdObj._deferred |
- |
- |
- |
-__all__ = ["MemCacheProtocol", "DEFAULT_PORT", "NoSuchCommand", "ClientError", |
- "ServerError"] |
- |