def scan(self, cursor=0, pattern=None, count=None): """The :meth:`~tredis.RedisClient.scan` command and the closely related commands :meth:`~tredis.RedisClient.sscan`, :meth:`~tredis.RedisClient.hscan` and :meth:`~tredis.RedisClient.zscan` are used in order to incrementally iterate over a collection of elements. - :meth:`~tredis.RedisClient.scan` iterates the set of keys in the currently selected Redis database. - :meth:`~tredis.RedisClient.sscan` iterates elements of Sets types. - :meth:`~tredis.RedisClient.hscan` iterates fields of Hash types and their associated values. - :meth:`~tredis.RedisClient.zscan` iterates elements of Sorted Set types and their associated scores. **Basic usage** :meth:`~tredis.RedisClient.scan` is a cursor based iterator. This means that at every call of the command, the server returns an updated cursor that the user needs to use as the cursor argument in the next call. An iteration starts when the cursor is set to ``0``, and terminates when the cursor returned by the server is ``0``. For more information on :meth:`~tredis.RedisClient.scan`, visit the `Redis docs on scan <http://redis.io/commands/scan>`_. .. note:: **Time complexity**: ``O(1)`` for every call. ``O(N)`` for a complete iteration, including enough command calls for the cursor to return back to ``0``. ``N`` is the number of elements inside the collection. :param int cursor: The server specified cursor value or ``0`` :param pattern: An optional pattern to apply for key matching :type pattern: :class:`str`, :class:`bytes` :param int count: An optional amount of work to perform in the scan :rtype: int, list :returns: A tuple containing the cursor and the list of keys :raises: :exc:`~tredis.exceptions.RedisError` """ def format_response(value): """Format the response from redis :param tuple value: The return response from redis :rtype: tuple(int, list) """ return int(value[0]), value[1] command = [b'SCAN', ascii(cursor).encode('ascii')] if pattern: command += [b'MATCH', pattern] if count: command += [b'COUNT', ascii(count).encode('ascii')] return self._execute(command, format_callback=format_response)
def wait(self, num_slaves, timeout=0): """his command blocks the current client until all the previous write commands are successfully transferred and acknowledged by at least the specified number of slaves. If the timeout, specified in milliseconds, is reached, the command returns even if the specified number of slaves were not yet reached. The command will always return the number of slaves that acknowledged the write commands sent before the :meth:`~tredis.RedisClient.wait` command, both in the case where the specified number of slaves are reached, or when the timeout is reached. .. note:: **Time complexity**: ``O(1)`` :param int num_slaves: Number of slaves to acknowledge previous writes :param int timeout: Timeout in milliseconds :rtype: int :raises: :exc:`~tredis.exceptions.RedisError` """ command = [b'WAIT', ascii(num_slaves).encode('ascii'), ascii(timeout).encode('ascii')] return self._execute(command)
def set(self, key, value, ex=None, px=None, nx=False, xx=False): """Set key to hold the string value. If key already holds a value, it is overwritten, regardless of its type. Any previous time to live associated with the key is discarded on successful :meth:`~tredis.RedisClient.set` operation. If the value is not one of :class:`str`, :class:`bytes`, or :class:`int`, a :exc:`ValueError` will be raised. .. note:: **Time complexity**: ``O(1)`` :param key: The key to remove :type key: :class:`str`, :class:`bytes` :param value: The value to set :type value: :class:`str`, :class:`bytes`, :class:`int` :param int ex: Set the specified expire time, in seconds :param int px: Set the specified expire time, in milliseconds :param bool nx: Only set the key if it does not already exist :param bool xx: Only set the key if it already exist :rtype: bool :raises: :exc:`~tredis.exceptions.RedisError` :raises: :exc:`ValueError` """ command = [b'SET', key, value] if ex: command += [b'EX', ascii(ex).encode('ascii')] if px: command += [b'PX', ascii(px).encode('ascii')] if nx: command.append(b'NX') if xx: command.append(b'XX') return self._execute(command, b'OK')
def wait(self, num_slaves, timeout=0): """his command blocks the current client until all the previous write commands are successfully transferred and acknowledged by at least the specified number of slaves. If the timeout, specified in milliseconds, is reached, the command returns even if the specified number of slaves were not yet reached. The command will always return the number of slaves that acknowledged the write commands sent before the :meth:`~tredis.RedisClient.wait` command, both in the case where the specified number of slaves are reached, or when the timeout is reached. .. note:: **Time complexity**: ``O(1)`` :param int num_slaves: Number of slaves to acknowledge previous writes :param int timeout: Timeout in milliseconds :rtype: int :raises: :exc:`~tredis.exceptions.RedisError` """ command = [ b'WAIT', ascii(num_slaves).encode('ascii'), ascii(timeout).encode('ascii') ] return self._execute(command)
def getrange(self, key, start, end): """Returns the bit value at offset in the string value stored at key. When offset is beyond the string length, the string is assumed to be a contiguous space with 0 bits. When key does not exist it is assumed to be an empty string, so offset is always out of range and the value is also assumed to be a contiguous space with 0 bits. .. versionadded:: 0.2.0 .. note:: **Time complexity**: ``O(N)`` where ``N`` is the length of the returned string. The complexity is ultimately determined by the returned length, but because creating a substring from an existing string is very cheap, it can be considered ``O(1)`` for small strings. :param key: The key to get the bit from :type key: :class:`str`, :class:`bytes` :param int start: The start position to evaluate in the string :param int end: The end position to evaluate in the string :rtype: bytes|None :raises: :exc:`~tredis.exceptions.RedisError` """ return self._execute([b'GETRANGE', key, ascii(start), ascii(end)])
def bitcount(self, key, start=None, end=None): """Count the number of set bits (population counting) in a string. By default all the bytes contained in the string are examined. It is possible to specify the counting operation only in an interval passing the additional arguments start and end. Like for the :meth:`~tredis.RedisClient.getrange` command start and end can contain negative values in order to index bytes starting from the end of the string, where ``-1`` is the last byte, ``-2`` is the penultimate, and so forth. Non-existent keys are treated as empty strings, so the command will return zero. .. versionadded:: 0.2.0 .. note:: **Time complexity**: ``O(N)`` :param key: The key to get :type key: :class:`str`, :class:`bytes` :param int start: The start position to evaluate in the string :param int end: The end position to evaluate in the string :rtype: int :raises: :exc:`~tredis.exceptions.RedisError`, :exc:`ValueError` """ command = [b'BITCOUNT', key] if start is not None and end is None: raise ValueError('Can not specify start without an end') elif start is None and end is not None: raise ValueError('Can not specify start without an end') elif start is not None and end is not None: command += [ascii(start), ascii(end)] return self._execute(command)
def scan(self, cursor=0, pattern=None, count=None): """The :meth:`~tredis.RedisClient.scan` command and the closely related commands :meth:`~tredis.RedisClient.sscan`, :meth:`~tredis.RedisClient.hscan` and :meth:`~tredis.RedisClient.zscan` are used in order to incrementally iterate over a collection of elements. - :meth:`~tredis.RedisClient.scan` iterates the set of keys in the currently selected Redis database. - :meth:`~tredis.RedisClient.sscan` iterates elements of Sets types. - :meth:`~tredis.RedisClient.hscan` iterates fields of Hash types and their associated values. - :meth:`~tredis.RedisClient.zscan` iterates elements of Sorted Set types and their associated scores. **Basic usage** :meth:`~tredis.RedisClient.scan` is a cursor based iterator. This means that at every call of the command, the server returns an updated cursor that the user needs to use as the cursor argument in the next call. An iteration starts when the cursor is set to ``0``, and terminates when the cursor returned by the server is ``0``. For more information on :meth:`~tredis.RedisClient.scan`, visit the `Redis docs on scan <http://redis.io/commands/scan>`_. .. note:: **Time complexity**: ``O(1)`` for every call. ``O(N)`` for a complete iteration, including enough command calls for the cursor to return back to ``0``. ``N`` is the number of elements inside the collection. :param int cursor: The server specified cursor value or ``0`` :param pattern: An optional pattern to apply for key matching :type pattern: :class:`str`, :class:`bytes` :param int count: An optional amount of work to perform in the scan :rtype: int, list :returns: A tuple containing the cursor and the list of keys :raises: :exc:`~tredis.exceptions.RedisError` """ def format_response(value): """Format the response from redis :param tuple value: The return response from redis :rtype: tuple(int, list) """ return int(value[0]), value[1] command = [b'SCAN', ascii(cursor).encode('ascii')] if pattern: command += [b'MATCH', pattern] if count: command += [b'COUNT', ascii(count).encode('ascii')] print(command) return self._execute(command, format_callback=format_response)
def bitpos(self, key, bit, start=None, end=None): """Return the position of the first bit set to ``1`` or ``0`` in a string. The position is returned, thinking of the string as an array of bits from left to right, where the first byte's most significant bit is at position 0, the second byte's most significant bit is at position ``8``, and so forth. The same bit position convention is followed by :meth:`~tredis.RedisClient.getbit` and :meth:`~tredis.RedisClient.setbit`. By default, all the bytes contained in the string are examined. It is possible to look for bits only in a specified interval passing the additional arguments start and end (it is possible to just pass start, the operation will assume that the end is the last byte of the string. However there are semantic differences as explained later). The range is interpreted as a range of bytes and not a range of bits, so ``start=0`` and ``end=2`` means to look at the first three bytes. Note that bit positions are returned always as absolute values starting from bit zero even when start and end are used to specify a range. Like for the :meth:`~tredis.RedisClient.getrange` command start and end can contain negative values in order to index bytes starting from the end of the string, where ``-1`` is the last byte, ``-2`` is the penultimate, and so forth. Non-existent keys are treated as empty strings. .. versionadded:: 0.2.0 .. note:: **Time complexity**: ``O(N)`` :param key: The key to get :type key: :class:`str`, :class:`bytes` :param int bit: The bit value to search for (``1`` or ``0``) :param int start: The start position to evaluate in the string :param int end: The end position to evaluate in the string :returns: The position of the first bit set to ``1`` or ``0`` :rtype: int :raises: :exc:`~tredis.exceptions.RedisError`, :exc:`ValueError` """ if 0 < bit > 1: raise ValueError('bit must be 1 or 0, not {}'.format(bit)) command = [b'BITPOS', key, ascii(bit)] if start is not None and end is None: raise ValueError('Can not specify start without an end') elif start is None and end is not None: raise ValueError('Can not specify start without an end') elif start is not None and end is not None: command += [ascii(start), ascii(end)] return self._execute(command)
def migrate(self, host, port, key, destination_db, timeout, copy=False, replace=False): """Atomically transfer a key from a source Redis instance to a destination Redis instance. On success the key is deleted from the original instance and is guaranteed to exist in the target instance. The command is atomic and blocks the two instances for the time required to transfer the key, at any given time the key will appear to exist in a given instance or in the other instance, unless a timeout error occurs. .. note:: **Time complexity**: This command actually executes a DUMP+DEL in the source instance, and a RESTORE in the target instance. See the pages of these commands for time complexity. Also an ``O(N)`` data transfer between the two instances is performed. :param host: The host to migrate the key to :type host: bytes, str :param int port: The port to connect on :param key: The key to migrate :type key: bytes, str :param int destination_db: The database number to select :param int timeout: The maximum idle time in milliseconds :param bool copy: Do not remove the key from the local instance :param bool replace: Replace existing key on the remote instance :rtype: bool :raises: :exc:`~tredis.exceptions.RedisError` """ command = [ b'MIGRATE', host, ascii(port).encode('ascii'), key, ascii(destination_db).encode('ascii'), ascii(timeout).encode('ascii') ] if copy is True: command.append(b'COPY') if replace is True: command.append(b'REPLACE') return self._execute(command, b'OK')
def spop(self, key, count=None): """Removes and returns one or more random elements from the set value store at key. This operation is similar to :meth:`~tredis.RedisClient.srandmember`, that returns one or more random elements from a set but does not remove it. The count argument will be available in a later version and is not available in 2.6, 2.8, 3.0 Redis 3.2 will be the first version where an optional count argument can be passed to :meth:`~tredis.RedisClient.spop` in order to retrieve multiple elements in a single call. The implementation is already available in the unstable branch. .. note:: **Time complexity**: Without the count argument ``O(1)``, otherwise ``O(N)`` where ``N`` is the absolute value of the passed count. :param key: The key to get one or more random members from :type key: :class:`str`, :class:`bytes` :param int count: The number of members to return :rtype: bytes, list :raises: :exc:`~tredis.exceptions.RedisError` """ command = [b'SPOP', key] if count: # pragma: nocover command.append(ascii(count).encode('ascii')) return self._execute(command)
def setex(self, key, seconds, value): """Set key to hold the string value and set key to timeout after a given number of seconds. :meth:`~tredis.RedisClient.setex` is atomic, and can be reproduced by using :meth:`~tredis.RedisClient.set` and :meth:`~tredis.RedisClient.expire` inside an :meth:`~tredis.RedisClient.multi` / :meth:`~tredis.RedisClient.exec` block. It is provided as a faster alternative to the given sequence of operations, because this operation is very common when Redis is used as a cache. An error is returned when seconds is invalid. .. versionadded:: 0.2.0 .. note:: **Time complexity**: ``O(1)`` :param key: The key to set :type key: :class:`str`, :class:`bytes` :param int seconds: Number of seconds for TTL :param value: The value to set :type value: :class:`str`, :class:`bytes` :rtype: bool :raises: :exc:`~tredis.exceptions.RedisError` """ return self._execute([b'SETEX', key, ascii(seconds), value], b'OK')
def srandmember(self, key, count=None): """When called with just the key argument, return a random element from the set value stored at key. Starting from Redis version 2.6, when called with the additional count argument, return an array of count distinct elements if count is positive. If called with a negative count the behavior changes and the command is allowed to return the same element multiple times. In this case the number of returned elements is the absolute value of the specified count. When called with just the key argument, the operation is similar to :meth:`~tredis.RedisClient.spop`, however while :meth:`~tredis.RedisClient.spop` also removes the randomly selected element from the set, :meth:`~tredis.RedisClient.srandmember` will just return a random element without altering the original set in any way. .. note:: **Time complexity**: Without the count argument ``O(1)``, otherwise ``O(N)`` where ``N`` is the absolute value of the passed count. :param key: The key to get one or more random members from :type key: :class:`str`, :class:`bytes` :param int count: The number of members to return :rtype: bytes, list :raises: :exc:`~tredis.exceptions.RedisError` """ command = [b'SRANDMEMBER', key] if count: command.append(ascii(count).encode('ascii')) return self._execute(command)
def select(self, index=0): """Select the DB with having the specified zero-based numeric index. New connections always use DB ``0``. :param int index: The database to select :rtype: bool :raises: :exc:`~tredis.exceptions.RedisError` """ return self._execute([b'SELECT', ascii(index).encode('ascii')], b'OK')
def _encode_resp(self, value): """Dynamically build the RESP payload based upon the list provided. :param mixed value: The list of command parts to encode :rtype: bytes """ if isinstance(value, bytes): return b''.join([b'$', ascii(len(value)).encode('ascii'), CRLF, value, CRLF]) elif isinstance(value, str): # pragma: nocover return self._encode_resp(value.encode('utf-8')) elif isinstance(value, int): return self._encode_resp(ascii(value).encode('ascii')) elif isinstance(value, list): output = [b'*', ascii(len(value)).encode('ascii'), CRLF] for item in value: output.append(self._encode_resp(item)) return b''.join(output) else: raise ValueError('Unsupported type: {0}'.format(type(value)))
def setbit(self, key, offset, bit): """Sets or clears the bit at offset in the string value stored at key. The bit is either set or cleared depending on value, which can be either 0 or 1. When key does not exist, a new string value is created. The string is grown to make sure it can hold a bit at offset. The offset argument is required to be greater than or equal to 0, and smaller than 2 :sup:`32` (this limits bitmaps to 512MB). When the string at key is grown, added bits are set to 0. .. warning:: When setting the last possible bit (offset equal to 2 :sup:`32` -1) and the string value stored at key does not yet hold a string value, or holds a small string value, Redis needs to allocate all intermediate memory which can block the server for some time. On a 2010 MacBook Pro, setting bit number 2 :sup:`32` -1 (512MB allocation) takes ~300ms, setting bit number 2 :sup:`30` -1 (128MB allocation) takes ~80ms, setting bit number 2 :sup:`28` -1 (32MB allocation) takes ~30ms and setting bit number 2 :sup:`26` -1 (8MB allocation) takes ~8ms. Note that once this first allocation is done, subsequent calls to :meth:`~tredis.RedisClient.setbit` for the same key will not have the allocation overhead. .. versionadded:: 0.2.0 .. note:: **Time complexity**: ``O(1)`` :param key: The key to get the bit from :type key: :class:`str`, :class:`bytes` :param int offset: The bit offset to fetch the bit from :param int bit: The value (``0`` or ``1``) to set for the bit :rtype: int :raises: :exc:`~tredis.exceptions.RedisError` """ if 0 < bit > 1: raise ValueError('bit must be 1 or 0, not {}'.format(bit)) return self._execute([b'SETBIT', key, ascii(offset), ascii(bit)])
def pexpire(self, key, timeout): """This command works exactly like :meth:`~tredis.RedisClient.pexpire` but the time to live of the key is specified in milliseconds instead of seconds. .. note:: **Time complexity**: ``O(1)`` :param key: The key to set an expiration for :type key: :class:`str`, :class:`bytes` :param int timeout: The number of milliseconds to set the timeout to :rtype: bool :raises: :exc:`~tredis.exceptions.RedisError` """ return self._execute( [b'PEXPIRE', key, ascii(timeout).encode('ascii')], 1)
def pexpireat(self, key, timestamp): """:meth:`~tredis.RedisClient.pexpireat` has the same effect and semantic as :meth:`~tredis.RedisClient.expireat`, but the Unix time at which the key will expire is specified in milliseconds instead of seconds. .. note:: **Time complexity**: ``O(1)`` :param key: The key to set an expiration for :type key: :class:`str`, :class:`bytes` :param int timestamp: The expiration UNIX epoch value in milliseconds :rtype: bool :raises: :exc:`~tredis.exceptions.RedisError` """ return self._execute( [b'PEXPIREAT', key, ascii(timestamp).encode('ascii')], 1)
def select(self, index=0): """Select the DB with having the specified zero-based numeric index. New connections always use DB ``0``. :param int index: The database to select :rtype: bool :raises: :exc:`~tredis.exceptions.RedisError` :raises: :exc:`~tredis.exceptions.InvalidClusterCommand` """ if self._clustering: raise exceptions.InvalidClusterCommand future = self._execute( [b'SELECT', ascii(index).encode('ascii')], b'OK') def on_selected(f): self._connection.database = index self.io_loop.add_future(future, on_selected) return future
def getbit(self, key, offset): """Returns the bit value at offset in the string value stored at key. When offset is beyond the string length, the string is assumed to be a contiguous space with 0 bits. When key does not exist it is assumed to be an empty string, so offset is always out of range and the value is also assumed to be a contiguous space with 0 bits. .. versionadded:: 0.2.0 .. note:: **Time complexity**: ``O(1)`` :param key: The key to get the bit from :type key: :class:`str`, :class:`bytes` :param int offset: The bit offset to fetch the bit from :rtype: bytes|None :raises: :exc:`~tredis.exceptions.RedisError` """ return self._execute([b'GETBIT', key, ascii(offset)])
def move(self, key, db): """Move key from the currently selected database (see :meth:`~tredis.RedisClient.select`) to the specified destination database. When key already exists in the destination database, or it does not exist in the source database, it does nothing. It is possible to use :meth:`~tredis.RedisClient.move` as a locking primitive because of this. .. note:: **Time complexity**: ``O(1)`` :param key: The key to move :type key: :class:`str`, :class:`bytes` :param int db: The database number :rtype: bool :raises: :exc:`~tredis.exceptions.RedisError` """ return self._execute([b'MOVE', key, ascii(db).encode('ascii')], 1)
def psetex(self, key, milliseconds, value): """:meth:`~tredis.RedisClient.psetex` works exactly like :meth:`~tredis.RedisClient.psetex` with the sole difference that the expire time is specified in milliseconds instead of seconds. .. versionadded:: 0.2.0 .. note:: **Time complexity**: ``O(1)`` :param key: The key to set :type key: :class:`str`, :class:`bytes` :param int milliseconds: Number of milliseconds for TTL :param value: The value to set :type value: :class:`str`, :class:`bytes` :rtype: bool :raises: :exc:`~tredis.exceptions.RedisError` """ return self._execute( [b'PSETEX', key, ascii(milliseconds), value], b'OK')
def psetex(self, key, milliseconds, value): """:meth:`~tredis.RedisClient.psetex` works exactly like :meth:`~tredis.RedisClient.psetex` with the sole difference that the expire time is specified in milliseconds instead of seconds. .. versionadded:: 0.2.0 .. note:: **Time complexity**: ``O(1)`` :param key: The key to set :type key: :class:`str`, :class:`bytes` :param int milliseconds: Number of milliseconds for TTL :param value: The value to set :type value: :class:`str`, :class:`bytes` :rtype: bool :raises: :exc:`~tredis.exceptions.RedisError` """ return self._execute([b'PSETEX', key, ascii(milliseconds), value], b'OK')
def expire(self, key, timeout): """Set a timeout on key. After the timeout has expired, the key will automatically be deleted. A key with an associated timeout is often said to be volatile in Redis terminology. The timeout is cleared only when the key is removed using the :meth:`~tredis.RedisClient.delete` method or overwritten using the :meth:`~tredis.RedisClient.set` or :meth:`~tredis.RedisClient.getset` methods. This means that all the operations that conceptually alter the value stored at the key without replacing it with a new one will leave the timeout untouched. For instance, incrementing the value of a key with :meth:`~tredis.RedisClient.incr`, pushing a new value into a list with :meth:`~tredis.RedisClient.lpush`, or altering the field value of a hash with :meth:`~tredis.RedisClient.hset` are all operations that will leave the timeout untouched. The timeout can also be cleared, turning the key back into a persistent key, using the :meth:`~tredis.RedisClient.persist` method. If a key is renamed with :meth:`~tredis.RedisClient.rename`, the associated time to live is transferred to the new key name. If a key is overwritten by :meth:`~tredis.RedisClient.rename`, like in the case of an existing key ``Key_A`` that is overwritten by a call like ``client.rename(Key_B, Key_A)`` it does not matter if the original ``Key_A`` had a timeout associated or not, the new key ``Key_A`` will inherit all the characteristics of ``Key_B``. .. note:: **Time complexity**: ``O(1)`` :param key: The key to set an expiration for :type key: :class:`str`, :class:`bytes` :param int timeout: The number of seconds to set the timeout to :rtype: bool :raises: :exc:`~tredis.exceptions.RedisError` """ return self._execute( [b'EXPIRE', key, ascii(timeout).encode('ascii')], 1)
def setrange(self, key, offset, value): """Overwrites part of the string stored at key, starting at the specified offset, for the entire length of value. If the offset is larger than the current length of the string at key, the string is padded with zero-bytes to make offset fit. Non-existing keys are considered as empty strings, so this command will make sure it holds a string large enough to be able to set value at offset. .. note:: The maximum offset that you can set is 2 :sup:`29` -1 (536870911), as Redis Strings are limited to 512 megabytes. If you need to grow beyond this size, you can use multiple keys. .. warning:: When setting the last possible byte and the string value stored at key does not yet hold a string value, or holds a small string value, Redis needs to allocate all intermediate memory which can block the server for some time. On a 2010 MacBook Pro, setting byte number 536870911 (512MB allocation) takes ~300ms, setting byte number 134217728 (128MB allocation) takes ~80ms, setting bit number 33554432 (32MB allocation) takes ~30ms and setting bit number 8388608 (8MB allocation) takes ~8ms. Note that once this first allocation is done, subsequent calls to :meth:`~tredis.RedisClient.setrange` for the same key will not have the allocation overhead. .. versionadded:: 0.2.0 .. note:: **Time complexity**: ``O(1)``, not counting the time taken to copy the new string in place. Usually, this string is very small so the amortized complexity is ``O(1)``. Otherwise, complexity is ``O(M)`` with ``M`` being the length of the value argument. :param key: The key to get the bit from :type key: :class:`str`, :class:`bytes` :param value: The value to set :type value: :class:`str`, :class:`bytes`, :class:`int` :returns: The length of the string after it was modified by the command :rtype: int :raises: :exc:`~tredis.exceptions.RedisError` """ return self._execute([b'SETRANGE', key, ascii(offset), value])
def restore(self, key, ttl, value, replace=False): """Create a key associated with a value that is obtained by deserializing the provided serialized value (obtained via :meth:`~tredis.RedisClient.dump`). If ``ttl`` is ``0`` the key is created without any expire, otherwise the specified expire time (in milliseconds) is set. :meth:`~tredis.RedisClient.restore` will return a ``Target key name is busy`` error when key already exists unless you use the :meth:`~tredis.RedisClient.restore` modifier (Redis 3.0 or greater). :meth:`~tredis.RedisClient.restore` checks the RDB version and data checksum. If they don't match an error is returned. .. note:: **Time complexity**: ``O(1)`` to create the new key and additional ``O(N*M)`` to reconstruct the serialized value, where ``N`` is the number of Redis objects composing the value and ``M`` their average size. For small string values the time complexity is thus ``O(1)+O(1*M)`` where ``M`` is small, so simply ``O(1)``. However for sorted set values the complexity is ``O(N*M*log(N))`` because inserting values into sorted sets is ``O(log(N))``. :param key: The key to get the TTL for :type key: :class:`str`, :class:`bytes` :param int ttl: The number of seconds to set the timeout to :param value: The value to restore to the key :type value: :class:`str`, :class:`bytes` :param bool replace: Replace a pre-existing key :rtype: bool :raises: :exc:`~tredis.exceptions.RedisError` """ command = [b'RESTORE', key, ascii(ttl).encode('ascii'), value] if replace: command.append(b'REPLACE') return self._execute(command, b'OK')
def expireat(self, key, timestamp): """:meth:`~tredis.RedisClient.expireat` has the same effect and semantic as :meth:`~tredis.RedisClient.expire`, but instead of specifying the number of seconds representing the TTL (time to live), it takes an absolute Unix timestamp (seconds since January 1, 1970). Please for the specific semantics of the command refer to the documentation of :meth:`~tredis.RedisClient.expire`. .. note:: **Time complexity**: ``O(1)`` :param key: The key to set an expiration for :type key: :class:`str`, :class:`bytes` :param int timestamp: The UNIX epoch value for the expiration :rtype: bool :raises: :exc:`~tredis.exceptions.RedisError` """ return self._execute( [b'EXPIREAT', key, ascii(timestamp).encode('ascii')], 1)
def incrby(self, key, increment): """Increments the number stored at key by increment. If the key does not exist, it is set to 0 before performing the operation. An error is returned if the key contains a value of the wrong type or contains a string that can not be represented as integer. This operation is limited to 64 bit signed integers. See :meth:`~tredis.RedisClient.incr` for extra information on increment/decrement operations. .. versionadded:: 0.2.0 .. note:: **Time complexity**: ``O(1)`` :param key: The key to increment :type key: :class:`str`, :class:`bytes` :param int increment: The amount to increment by :returns: The value of key after the increment :rtype: int :raises: :exc:`~tredis.exceptions.RedisError` """ return self._execute([b'INCRBY', key, ascii(increment)])
def incrbyfloat(self, key, increment): """Increment the string representing a floating point number stored at key by the specified increment. If the key does not exist, it is set to 0 before performing the operation. An error is returned if one of the following conditions occur: - The key contains a value of the wrong type (not a string). - The current key content or the specified increment are not parsable as a double precision floating point number. If the command is successful the new incremented value is stored as the new value of the key (replacing the old one), and returned to the caller as a string. Both the value already contained in the string key and the increment argument can be optionally provided in exponential notation, however the value computed after the increment is stored consistently in the same format, that is, an integer number followed (if needed) by a dot, and a variable number of digits representing the decimal part of the number. Trailing zeroes are always removed. The precision of the output is fixed at 17 digits after the decimal point regardless of the actual internal precision of the computation. .. versionadded:: 0.2.0 .. note:: **Time complexity**: ``O(1)`` :param key: The key to increment :type key: :class:`str`, :class:`bytes` :param float increment: The amount to increment by :returns: The value of key after the increment :rtype: bytes :raises: :exc:`~tredis.exceptions.RedisError` """ return self._execute([b'INCRBYFLOAT', key, ascii(increment)])
def on_connect(response): """Invoked when the socket stream has connected :param response: The connection response future :type response: :class:`~tornado.concurrent.Future` """ exc = response.exception() if exc: return future.set_exception(exceptions.ConnectError(str(exc))) self._stream = response.result() self._stream.set_close_callback(self._on_closed) if not self._default_db: return future.set_result(True) def on_written(): select_future = concurrent.TracebackFuture() self._get_response(select_future) self._ioloop.add_future(select_future, on_selected) LOGGER.debug('Selecting the default db: %r', self._default_db) command = self._build_command(['SELECT', ascii(self._default_db)]) self._stream.write(command, on_written)
def sort(self, key, by=None, external=None, offset=0, limit=None, order=None, alpha=False, store_as=None): """Returns or stores the elements contained in the list, set or sorted set at key. By default, sorting is numeric and elements are compared by their value interpreted as double precision floating point number. The ``external`` parameter is used to specify the `GET <http://redis.io/commands/sort#retrieving-external-keys>_` parameter for retrieving external keys. It can be a single string or a list of strings. .. note:: **Time complexity**: ``O(N+M*log(M))`` where ``N`` is the number of elements in the list or set to sort, and ``M`` the number of returned elements. When the elements are not sorted, complexity is currently ``O(N)`` as there is a copy step that will be avoided in next releases. :param key: The key to get the refcount for :type key: :class:`str`, :class:`bytes` :param by: The optional pattern for external sorting keys :type by: :class:`str`, :class:`bytes` :param external: Pattern or list of patterns to return external keys :type external: :class:`str`, :class:`bytes`, list :param int offset: The starting offset when using limit :param int limit: The number of elements to return :param order: The sort order - one of ``ASC`` or ``DESC`` :type order: :class:`str`, :class:`bytes` :param bool alpha: Sort the results lexicographically :param store_as: When specified, the key to store the results as :type store_as: :class:`str`, :class:`bytes`, None :rtype: list|int :raises: :exc:`~tredis.exceptions.RedisError` :raises: :exc:`ValueError` """ if order and order not in [b'ASC', b'DESC', 'ASC', 'DESC']: raise ValueError('invalid sort order "{}"'.format(order)) command = [b'SORT', key] if by: command += [b'BY', by] if external and isinstance(external, list): for entry in external: command += [b'GET', entry] elif external: command += [b'GET', external] if limit: command += [b'LIMIT', ascii(offset).encode('utf-8'), ascii(limit).encode('utf-8')] if order: command.append(order) if alpha is True: command.append(b'ALPHA') if store_as: command += [b'STORE', store_as] return self._execute(command)
def sort(self, key, by=None, external=None, offset=0, limit=None, order=None, alpha=False, store_as=None): """Returns or stores the elements contained in the list, set or sorted set at key. By default, sorting is numeric and elements are compared by their value interpreted as double precision floating point number. The ``external`` parameter is used to specify the `GET <http://redis.io/commands/sort#retrieving-external-keys>_` parameter for retrieving external keys. It can be a single string or a list of strings. .. note:: **Time complexity**: ``O(N+M*log(M))`` where ``N`` is the number of elements in the list or set to sort, and ``M`` the number of returned elements. When the elements are not sorted, complexity is currently ``O(N)`` as there is a copy step that will be avoided in next releases. :param key: The key to get the refcount for :type key: :class:`str`, :class:`bytes` :param by: The optional pattern for external sorting keys :type by: :class:`str`, :class:`bytes` :param external: Pattern or list of patterns to return external keys :type external: :class:`str`, :class:`bytes`, list :param int offset: The starting offset when using limit :param int limit: The number of elements to return :param order: The sort order - one of ``ASC`` or ``DESC`` :type order: :class:`str`, :class:`bytes` :param bool alpha: Sort the results lexicographically :param store_as: When specified, the key to store the results as :type store_as: :class:`str`, :class:`bytes`, None :rtype: list|int :raises: :exc:`~tredis.exceptions.RedisError` :raises: :exc:`ValueError` """ if order and order not in [b'ASC', b'DESC', 'ASC', 'DESC']: raise ValueError('invalid sort order "{}"'.format(order)) command = [b'SORT', key] if by: command += [b'BY', by] if external and isinstance(external, list): for entry in external: command += [b'GET', entry] elif external: command += [b'GET', external] if limit: command += [ b'LIMIT', ascii(offset).encode('utf-8'), ascii(limit).encode('utf-8') ] if order: command.append(order) if alpha is True: command.append(b'ALPHA') if store_as: command += [b'STORE', store_as] return self._execute(command)