mirror of
https://github.com/kennethreitz-archive/redis-docs.git
synced 2026-06-05 23:40:18 +00:00
added imported docs
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**AppendCommand: Contents**
|
||||
`APPEND \_key\_ \_value\_ <#APPEND%20_key_%20_value_>`_
|
||||
`Return value <#Return%20value>`_
|
||||
`Examples <#Examples>`_
|
||||
AppendCommand
|
||||
=============
|
||||
|
||||
#sidebar `StringCommandsSidebar <StringCommandsSidebar.html>`_
|
||||
APPEND \_key\_ \_value\_
|
||||
========================
|
||||
|
||||
*Time complexity: O(1). The amortized time complexity is O(1) assuming the appended value is small and the already present value is of any size, since the dynamic string library used by Redis will double the free space available on every reallocation.*
|
||||
If the *key* already exists and is a string, this command appends
|
||||
theprovided value at the end of the string.If the *key* does not
|
||||
exist it is created and set as an empty string, soAPPEND will be
|
||||
very similar to SET in this special case.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Integer reply <ReplyTypes.html>`_, specifically the total length
|
||||
of the string after the append operation.
|
||||
Examples
|
||||
--------
|
||||
|
||||
::
|
||||
|
||||
redis> exists mykey
|
||||
(integer) 0
|
||||
redis> append mykey "Hello "
|
||||
(integer) 6
|
||||
redis> append mykey "World"
|
||||
(integer) 11
|
||||
redis> get mykey
|
||||
"Hello World"
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,116 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**AppendOnlyFileHowto: Contents**
|
||||
`Append Only File HOWTO <#Append%20Only%20File%20HOWTO>`_
|
||||
`General Information <#General%20Information>`_
|
||||
`Log rewriting <#Log%20rewriting>`_
|
||||
`Wait... but how does this work? <#Wait...%20but%20how%20does%20this%20work?>`_
|
||||
`How durable is the append only file? <#How%20durable%20is%20the%20append%20only%20file?>`_
|
||||
`What should I do if my Append Only File gets corrupted? <#What%20should%20I%20do%20if%20my%20Append%20Only%20File%20gets%20corrupted?>`_
|
||||
AppendOnlyFileHowto
|
||||
===================
|
||||
|
||||
#sidebar `RedisGuides <RedisGuides.html>`_
|
||||
Append Only File HOWTO
|
||||
======================
|
||||
|
||||
General Information
|
||||
-------------------
|
||||
|
||||
Append only file is an alternative durability option for Redis.
|
||||
What this mean? Let's start with some fact:
|
||||
|
||||
- For default Redis saves snapshots of the dataset on disk, in a
|
||||
binary file called dump.rdb (by default at least). For instance you
|
||||
can configure Redis to save the dataset every 60 seconds if there
|
||||
are at least 100 changes in the dataset, or every 1000 seconds if
|
||||
there is at least a single change in the dataset. This is known as
|
||||
"Snapshotting".
|
||||
- Snapshotting is not very durable. If your computer running Redis
|
||||
stops, your power line fails, or you write killall -9 redis-server
|
||||
for a mistake, the latest data written on Redis will get lost.
|
||||
There are applications where this is not a big deal. There are
|
||||
applications where this is not acceptable and Redis **was** not an
|
||||
option for this applications.
|
||||
|
||||
What is the solution? To use append only file as alternative to
|
||||
snapshotting. How it works?
|
||||
|
||||
- It is an 1.1 only feature.
|
||||
- You have to turn it on editing the configuration file. Just make
|
||||
sure you have "appendonly yes" somewhere.
|
||||
- Append only files work this way: every time Redis receive a
|
||||
command that changes the dataset (for instance a SET or LPUSH
|
||||
command) it appends this command in the append only file. When you
|
||||
restart Redis it will first **re-play** the append only file to
|
||||
rebuild the state.
|
||||
|
||||
Log rewriting
|
||||
-------------
|
||||
|
||||
As you can guess... the append log file gets bigger and bigger,
|
||||
every time there is a new operation changing the dataset. Even if
|
||||
you set always the same key "mykey" to the values of "1", "2", "3",
|
||||
... up to 10000000000 in the end you'll have just a single key in
|
||||
the dataset, just a few bytes! but how big will be the append log
|
||||
file? Very very big.
|
||||
So Redis supports an interesting feature: it is able to rebuild the
|
||||
append log file, in background, without to stop processing client
|
||||
commands. The key is the command
|
||||
`BGREWRITEAOF <BGREWRITEAOF.html>`_. This command basically is able
|
||||
to use the dataset in memory in order to rewrite the shortest
|
||||
sequence of commands able to rebuild the exact dataset that is
|
||||
currently in memory.
|
||||
So from time to time when the log gets too big, try this command.
|
||||
It's safe as if it fails you will not lost your old log (but you
|
||||
can make a backup copy given that currently 1.1 is still in beta!).
|
||||
Wait... but how does this work?
|
||||
-------------------------------
|
||||
|
||||
Basically it uses the same fork() copy-on-write trick that
|
||||
snapshotting already uses. This is how the algorithm works:
|
||||
|
||||
- Redis forks, so now we have a child and a parent.
|
||||
- The child starts writing the new append log file in a temporary
|
||||
file.
|
||||
- The parent accumulates all the new changes in an in-memory
|
||||
buffer (but at the same time it writes the new changes in the
|
||||
**old** append only file, so if the rewriting fails, we are safe).
|
||||
- When the child finished to rewrite the file, the parent gets a
|
||||
signal, and append the in-memory buffer at the end of the file
|
||||
generated by the child.
|
||||
- Profit! Now Redis atomically renames the old file into the new
|
||||
one, and starts appending new data into the new file.
|
||||
|
||||
How durable is the append only file?
|
||||
------------------------------------
|
||||
|
||||
Check redis.conf, you can configure how many times Redis will
|
||||
fsync() data on disk. There are three options:
|
||||
|
||||
- Fsync() every time a new command is appended to the append log
|
||||
file. Very very slow, very safe.
|
||||
- Fsync() one time every second. Fast enough, and you can lose 1
|
||||
second of data if there is a disaster.
|
||||
- Never fsync(), just put your data in the hands of the Operating
|
||||
System. The faster and unsafer method.
|
||||
|
||||
The suggested (and default) policy is "everysec". It is both very
|
||||
fast and pretty safe. The "always" policy is very slow in practice,
|
||||
even if it was improved in Redis 2.0.0 there is no way to make
|
||||
fsync() faster than it is.
|
||||
What should I do if my Append Only File gets corrupted?
|
||||
-------------------------------------------------------
|
||||
|
||||
It is possible that the server crashes while writing the AOF file
|
||||
(this still should never lead to inconsistencies) corrupting the
|
||||
file in a way that is no longer loadable by Redis. When this
|
||||
happens you can fix this problem using the following procedure:
|
||||
|
||||
- Make a backup copy of your AOF file.
|
||||
- Fix the original file with: ./redis-check-aof --fix
|
||||
``<filename>``
|
||||
- Optionally use diff -u to check what is the difference between
|
||||
two files.
|
||||
- Restart the server with the fixed file.
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,30 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**AuthCommand: Contents**
|
||||
`AUTH \_password\_ <#AUTH%20_password_>`_
|
||||
`Return value <#Return%20value>`_
|
||||
AuthCommand
|
||||
===========
|
||||
|
||||
#sidebar
|
||||
`ConnectionHandlingSidebar <ConnectionHandlingSidebar.html>`_
|
||||
AUTH \_password\_
|
||||
=================
|
||||
|
||||
Request for authentication in a password protected Redis server.A
|
||||
Redis server can be instructed to require a password before to
|
||||
allow clientsto issue commands. This is done using the
|
||||
*requirepass* directive in theRedis configuration file.
|
||||
|
||||
If the password given by the client is correct the server replies
|
||||
withan OK status code reply and starts accepting commands from the
|
||||
client.Otherwise an error is returned and the clients needs to try
|
||||
a new password.Note that for the high performance nature of Redis
|
||||
it is possible to trya lot of passwords in parallel in very short
|
||||
time, so make sure to generatea strong and very long password so
|
||||
that this attack is infeasible.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Status code reply <ReplyTypes.html>`_
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,137 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**Benchmarks: Contents**
|
||||
`How Fast is Redis? <#How%20Fast%20is%20Redis?>`_
|
||||
`Latency percentiles <#Latency%20percentiles>`_
|
||||
Benchmarks
|
||||
==========
|
||||
|
||||
How Fast is Redis?
|
||||
==================
|
||||
|
||||
Redis includes the ``redis-benchmark`` utility that simulates
|
||||
`SETs <SETs.html>`_/GETs done by N clients at the same time sending
|
||||
M total queries (it is similar to the Apache's ``ab`` utility).
|
||||
Below you'll find the full output of the benchmark executed against
|
||||
a Linux box.
|
||||
|
||||
- The test was done with 50 simultaneous clients performing 100000
|
||||
requests.
|
||||
- The value SET and GET is a 256 bytes string.
|
||||
- The Linux box is running **Linux 2.6**, it's
|
||||
**Xeon X3320 2.5Ghz**.
|
||||
- Text executed using the loopback interface (127.0.0.1).
|
||||
|
||||
Results:
|
||||
**about 110000 `SETs <SETs.html>`_ per second, about 81000 GETs per second.**
|
||||
Latency percentiles
|
||||
===================
|
||||
|
||||
::
|
||||
|
||||
./redis-benchmark -n 100000
|
||||
|
||||
====== SET ======
|
||||
100007 requests completed in 0.88 seconds
|
||||
50 parallel clients
|
||||
3 bytes payload
|
||||
keep alive: 1
|
||||
|
||||
58.50% <= 0 milliseconds
|
||||
99.17% <= 1 milliseconds
|
||||
99.58% <= 2 milliseconds
|
||||
99.85% <= 3 milliseconds
|
||||
99.90% <= 6 milliseconds
|
||||
100.00% <= 9 milliseconds
|
||||
114293.71 requests per second
|
||||
|
||||
====== GET ======
|
||||
100000 requests completed in 1.23 seconds
|
||||
50 parallel clients
|
||||
3 bytes payload
|
||||
keep alive: 1
|
||||
|
||||
43.12% <= 0 milliseconds
|
||||
96.82% <= 1 milliseconds
|
||||
98.62% <= 2 milliseconds
|
||||
100.00% <= 3 milliseconds
|
||||
81234.77 requests per second
|
||||
|
||||
====== INCR ======
|
||||
100018 requests completed in 1.46 seconds
|
||||
50 parallel clients
|
||||
3 bytes payload
|
||||
keep alive: 1
|
||||
|
||||
32.32% <= 0 milliseconds
|
||||
96.67% <= 1 milliseconds
|
||||
99.14% <= 2 milliseconds
|
||||
99.83% <= 3 milliseconds
|
||||
99.88% <= 4 milliseconds
|
||||
99.89% <= 5 milliseconds
|
||||
99.96% <= 9 milliseconds
|
||||
100.00% <= 18 milliseconds
|
||||
68458.59 requests per second
|
||||
|
||||
====== LPUSH ======
|
||||
100004 requests completed in 1.14 seconds
|
||||
50 parallel clients
|
||||
3 bytes payload
|
||||
keep alive: 1
|
||||
|
||||
62.27% <= 0 milliseconds
|
||||
99.74% <= 1 milliseconds
|
||||
99.85% <= 2 milliseconds
|
||||
99.86% <= 3 milliseconds
|
||||
99.89% <= 5 milliseconds
|
||||
99.93% <= 7 milliseconds
|
||||
99.96% <= 9 milliseconds
|
||||
100.00% <= 22 milliseconds
|
||||
100.00% <= 208 milliseconds
|
||||
88109.25 requests per second
|
||||
|
||||
====== LPOP ======
|
||||
100001 requests completed in 1.39 seconds
|
||||
50 parallel clients
|
||||
3 bytes payload
|
||||
keep alive: 1
|
||||
|
||||
54.83% <= 0 milliseconds
|
||||
97.34% <= 1 milliseconds
|
||||
99.95% <= 2 milliseconds
|
||||
99.96% <= 3 milliseconds
|
||||
99.96% <= 4 milliseconds
|
||||
100.00% <= 9 milliseconds
|
||||
100.00% <= 208 milliseconds
|
||||
71994.96 requests per second
|
||||
|
||||
Notes: changing the payload from 256 to 1024 or 4096 bytes does not
|
||||
change the numbers significantly (but reply packets are glued
|
||||
together up to 1024 bytes so GETs may be slower with big payloads).
|
||||
The same for the number of clients, from 50 to 256 clients I got
|
||||
the same numbers. With only 10 clients it starts to get a bit
|
||||
slower.
|
||||
You can expect different results from different boxes. For example
|
||||
a low profile box like
|
||||
**Intel core duo T5500 clocked at 1.66Ghz running Linux 2.6** will
|
||||
output the following:
|
||||
::
|
||||
|
||||
./redis-benchmark -q -n 100000
|
||||
SET: 53684.38 requests per second
|
||||
GET: 45497.73 requests per second
|
||||
INCR: 39370.47 requests per second
|
||||
LPUSH: 34803.41 requests per second
|
||||
LPOP: 37367.20 requests per second
|
||||
|
||||
Another one using a 64 bit box, a Xeon L5420 clocked at 2.5 Ghz:
|
||||
::
|
||||
|
||||
./redis-benchmark -q -n 100000
|
||||
PING: 111731.84 requests per second
|
||||
SET: 108114.59 requests per second
|
||||
GET: 98717.67 requests per second
|
||||
INCR: 95241.91 requests per second
|
||||
LPUSH: 104712.05 requests per second
|
||||
LPOP: 93722.59 requests per second
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,31 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**BgrewriteaofCommand: Contents**
|
||||
`BGREWRITEAOF <#BGREWRITEAOF>`_
|
||||
`Return value <#Return%20value>`_
|
||||
BgrewriteaofCommand
|
||||
===================
|
||||
|
||||
#sidebar `ControlCommandsSidebar <ControlCommandsSidebar.html>`_
|
||||
BGREWRITEAOF
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Please for detailed information about the Redis Append Only File
|
||||
check`the Append Only File Howto <AppendOnlyFileHowto.html>`_.
|
||||
|
||||
BGREWRITEAOF rewrites the Append Only File in background when it
|
||||
gets toobig. The Redis Append Only File is a Journal, so every
|
||||
operation modifyingthe dataset is logged in the Append Only File
|
||||
(and replayed at startup).This means that the Append Only File
|
||||
always grows. In order to rebuildits content the BGREWRITEAOF
|
||||
creates a new version of the append only filestarting directly form
|
||||
the dataset in memory in order to guarantee thegeneration of the
|
||||
minimal number of commands needed to rebuild the database.
|
||||
|
||||
The `Append Only File Howto <AppendOnlyFileHowto.html>`_ contains
|
||||
further details.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Status code reply <ReplyTypes.html>`_
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,22 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**BgsaveCommand: Contents**
|
||||
`BGSAVE <#BGSAVE>`_
|
||||
`Return value <#Return%20value>`_
|
||||
BgsaveCommand
|
||||
=============
|
||||
|
||||
#sidebar `ControlCommandsSidebar <ControlCommandsSidebar.html>`_
|
||||
BGSAVE
|
||||
======
|
||||
|
||||
Save the DB in background. The OK code is immediately
|
||||
returned.Redis forks, the parent continues to server the clients,
|
||||
the childsaves the DB on disk then exit. A client my be able to
|
||||
check if theoperation succeeded using the
|
||||
`LASTSAVE <LastsaveCommand.html>`_ command.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Status code reply <ReplyTypes.html>`_
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,100 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**BlpopCommand: Contents**
|
||||
`BLPOP \_key1\_ \_key2\_ ... \_keyN\_ \_timeout\_ (Redis > <#BLPOP%20_key1_%20_key2_%20...%20_keyN_%20_timeout_%20(Redis%20%3E>`_
|
||||
`BRPOP \_key1\_ \_key2\_ ... \_keyN\_ \_timeout\_ (Redis > <#BRPOP%20_key1_%20_key2_%20...%20_keyN_%20_timeout_%20(Redis%20%3E>`_
|
||||
`Non blocking behavior <#Non%20blocking%20behavior>`_
|
||||
`Blocking behavior <#Blocking%20behavior>`_
|
||||
`Multiple clients blocking for the same keys <#Multiple%20clients%20blocking%20for%20the%20same%20keys>`_
|
||||
`blocking POP inside a MULTI/EXEC transaction <#blocking%20POP%20inside%20a%20MULTI/EXEC%20transaction>`_
|
||||
`Return value <#Return%20value>`_
|
||||
BlpopCommand
|
||||
============
|
||||
|
||||
#sidebar `ListCommandsSidebar <ListCommandsSidebar.html>`_
|
||||
BLPOP \_key1\_ \_key2\_ ... \_keyN\_ \_timeout\_ (Redis >
|
||||
=========================================================
|
||||
|
||||
1.3.1) =
|
||||
BRPOP \_key1\_ \_key2\_ ... \_keyN\_ \_timeout\_ (Redis >
|
||||
=========================================================
|
||||
|
||||
1.3.1) = *Time complexity: O(1)*
|
||||
BLPOP (and BRPOP) is a blocking list pop primitive. You can see
|
||||
this commandsas blocking versions of `LPOP <LpopCommand.html>`_ and
|
||||
`RPOP <LpopCommand.html>`_ able toblock if the specified keys don't
|
||||
exist or contain empty lists.
|
||||
|
||||
The following is a description of the exact semantic. We describe
|
||||
BLPOP butthe two commands are identical, the only difference is
|
||||
that BLPOP pops theelement from the left (head) of the list, and
|
||||
BRPOP pops from the right (tail).
|
||||
|
||||
Non blocking behavior
|
||||
---------------------
|
||||
|
||||
When BLPOP is called, if at least one of the specified keys contain
|
||||
a nonempty list, an element is popped from the head of the list and
|
||||
returned tothe caller together with the name of the key (BLPOP
|
||||
returns a two elementsarray, the first element is the key, the
|
||||
second the popped value).
|
||||
|
||||
Keys are scanned from left to right, so for instance if youissue
|
||||
**BLPOP list1 list2 list3 0** against a dataset where **list1**
|
||||
does notexist but **list2** and **list3** contain non empty lists,
|
||||
BLPOP guaranteesto return an element from the list stored at
|
||||
**list2** (since it is the firstnon empty list starting from the
|
||||
left).
|
||||
|
||||
Blocking behavior
|
||||
-----------------
|
||||
|
||||
If none of the specified keys exist or contain non empty lists,
|
||||
BLPOPblocks until some other client performs a
|
||||
`LPUSH <RpushCommand.html>`_ oran `RPUSH <RpushCommand.html>`_
|
||||
operation against one of the lists.
|
||||
|
||||
Once new data is present on one of the lists, the client finally
|
||||
returnswith the name of the key unblocking it and the popped
|
||||
value.
|
||||
|
||||
When blocking, if a non-zero timeout is specified, the client will
|
||||
unblockreturning a nil special value if the specified amount of
|
||||
seconds passedwithout a push operation against at least one of the
|
||||
specified keys.
|
||||
|
||||
The timeout argument is interpreted as an integer value. A timeout
|
||||
of zero means instead to block forever.
|
||||
|
||||
Multiple clients blocking for the same keys
|
||||
-------------------------------------------
|
||||
|
||||
Multiple clients can block for the same key. They are put intoa
|
||||
queue, so the first to be served will be the one that started to
|
||||
waitearlier, in a first-blpopping first-served fashion.
|
||||
|
||||
blocking POP inside a MULTI/EXEC transaction
|
||||
--------------------------------------------
|
||||
|
||||
BLPOP and BRPOP can be used with pipelining (sending multiple
|
||||
commands and reading the replies in batch), but it does not make
|
||||
sense to use BLPOP or BRPOP inside a MULTI/EXEC block (a Redis
|
||||
transaction).
|
||||
|
||||
The behavior of BLPOP inside MULTI/EXEC when the list is empty is
|
||||
to return a multi-bulk nil reply, exactly what happens when the
|
||||
timeout is reached. If you like science fiction, think at it like
|
||||
if inside MULTI/EXEC the time will flow at infinite speed :)
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
BLPOP returns a two-elements array via a multi bulk reply in order
|
||||
to returnboth the unblocking key and the popped value.
|
||||
|
||||
When a non-zero timeout is specified, and the BLPOP operation timed
|
||||
out,the return value is a nil multi bulk reply. Most client values
|
||||
will returnfalse or nil accordingly to the programming language
|
||||
used.
|
||||
|
||||
`Multi bulk reply <ReplyTypes.html>`_
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,38 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**BrpoplpushCommand: Contents**
|
||||
`BRPOPLPUSH \_srckey\_ \_dstkey\_ \_timeout\_ (Redis > <#BRPOPLPUSH%20_srckey_%20_dstkey_%20_timeout_%20(Redis%20%3E>`_
|
||||
`Return value <#Return%20value>`_
|
||||
BrpoplpushCommand
|
||||
=================
|
||||
|
||||
BRPOPLPUSH \_srckey\_ \_dstkey\_ \_timeout\_ (Redis >
|
||||
=====================================================
|
||||
|
||||
2.1.8) = *Time complexity: O(1)*
|
||||
Blocking version of the `RPOPLPUSH <RpoplpushCommand.html>`_
|
||||
command. Atomically removes and returnsthe last element (tail) of
|
||||
the source list at *srckey*, and as a side effect pushes the
|
||||
returned element in the head of the list at *dstkey*.
|
||||
|
||||
If the source list is empty, the client blocks until another client
|
||||
pushes against the source list. Of course in such a case the push
|
||||
operation against the destination list will be performed after the
|
||||
command unblocks detecting a push against the source list.
|
||||
Note that the command returns an error if the target key already
|
||||
exists but is not a list. The error is delayed at the time the push
|
||||
operation is attempted, that is, immediately if the source list is
|
||||
not empty, or when the first push against the source list happens
|
||||
in the case the command would block.
|
||||
The timeout value can be 0 or a positive integer value. When it is
|
||||
zero the command will block forever, until something is pushed
|
||||
against *srckey*. Otherwise the command will wait the specified
|
||||
number of seconds at max, returning an nil value when the timeout
|
||||
expires.
|
||||
The source and destination of the list can be the same, having the
|
||||
effect of rotating the list. Please check
|
||||
`RPOPLPUSH <RpoplpushCommand.html>`_ for more information.
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Bulk reply <ReplyTypes.html>`_
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,420 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**CommandReference: Contents**
|
||||
`Categorized Command List <#Categorized%20Command%20List>`_
|
||||
`Connection handling <#Connection%20handling>`_
|
||||
`Commands operating on all value types <#Commands%20operating%20on%20all%20value%20types>`_
|
||||
`Commands operating on string values <#Commands%20operating%20on%20string%20values>`_
|
||||
`Commands operating on lists <#Commands%20operating%20on%20lists>`_
|
||||
`Commands operating on sets <#Commands%20operating%20on%20sets>`_
|
||||
`Commands operating on sorted zsets (sorted sets) <#Commands%20operating%20on%20sorted%20zsets%20(sorted%20sets)>`_
|
||||
`Commands operating on hashes <#Commands%20operating%20on%20hashes>`_
|
||||
`Sorting <#Sorting>`_
|
||||
`Transactions <#Transactions>`_
|
||||
`Publish/Subscribe <#Publish/Subscribe>`_
|
||||
`Persistence control commands <#Persistence%20control%20commands>`_
|
||||
`Remote server control commands <#Remote%20server%20control%20commands>`_
|
||||
CommandReference
|
||||
================
|
||||
|
||||
= Redis Command Reference =
|
||||
Every command name links to a specific wiki page describing the
|
||||
behavior of the command.
|
||||
Categorized Command List
|
||||
------------------------
|
||||
|
||||
Connection handling
|
||||
-------------------
|
||||
|
||||
**Command**
|
||||
**Parameters**
|
||||
**Description**
|
||||
`QUIT <QuitCommand.html>`_
|
||||
-
|
||||
close the connection
|
||||
`AUTH <AuthCommand.html>`_
|
||||
*password*
|
||||
simple password authentication if enabled
|
||||
Commands operating on all value types
|
||||
-------------------------------------
|
||||
|
||||
**Command**
|
||||
**Parameters**
|
||||
**Description**
|
||||
`EXISTS <ExistsCommand.html>`_
|
||||
*key*
|
||||
test if a key exists
|
||||
`DEL <DelCommand.html>`_
|
||||
*key*
|
||||
delete a key
|
||||
`TYPE <TypeCommand.html>`_
|
||||
*key*
|
||||
return the type of the value stored at key
|
||||
`KEYS <KeysCommand.html>`_
|
||||
*pattern*
|
||||
return all the keys matching a given pattern
|
||||
`RANDOMKEY <RandomkeyCommand.html>`_
|
||||
-
|
||||
return a random key from the key space
|
||||
`RENAME <RenameCommand.html>`_
|
||||
*oldname* *newname*
|
||||
rename the old key in the new one, destroying the newname key if it
|
||||
already exists
|
||||
`RENAMENX <RenamenxCommand.html>`_
|
||||
*oldname* *newname*
|
||||
rename the *oldname* key to *newname*, if the *newname* key does
|
||||
not already exist
|
||||
`DBSIZE <DbsizeCommand.html>`_
|
||||
-
|
||||
return the number of keys in the current db
|
||||
`EXPIRE <ExpireCommand.html>`_
|
||||
-
|
||||
set a time to live in seconds on a key
|
||||
`PERSIST <ExpireCommand.html>`_
|
||||
-
|
||||
remove the expire from a key
|
||||
`TTL <TtlCommand.html>`_
|
||||
-
|
||||
get the time to live in seconds of a key
|
||||
`SELECT <SelectCommand.html>`_
|
||||
*index*
|
||||
Select the DB with the specified index
|
||||
`MOVE <MoveCommand.html>`_
|
||||
*key* *dbindex*
|
||||
Move the key from the currently selected DB to the *dbindex* DB
|
||||
`FLUSHDB <FlushdbCommand.html>`_
|
||||
-
|
||||
Remove all the keys from the currently selected DB
|
||||
`FLUSHALL <FlushallCommand.html>`_
|
||||
-
|
||||
Remove all the keys from all the databases
|
||||
Commands operating on string values
|
||||
-----------------------------------
|
||||
|
||||
**Command**
|
||||
**Parameters**
|
||||
**Description**
|
||||
`SET <SetCommand.html>`_
|
||||
*key* *value*
|
||||
Set a *key* to a string *value*
|
||||
`GET <GetCommand.html>`_
|
||||
*key*
|
||||
Return the string value of the *key*
|
||||
`GETSET <GetsetCommand.html>`_
|
||||
*key* *value*
|
||||
Set a key to a string returning the old value of the key
|
||||
`SETNX <SetnxCommand.html>`_
|
||||
*key* *value*
|
||||
Set a key to a string value if the key does not exist
|
||||
`SETEX <SetexCommand.html>`_
|
||||
*key* *time* *value*
|
||||
Set+Expire combo command
|
||||
`SETBIT <SetbitCommand.html>`_
|
||||
*key* *offset* *value*
|
||||
Set bit at *offset* to *value*
|
||||
`GETBIT <GetbitCommand.html>`_
|
||||
*key* *offset*
|
||||
Return bit value at *offset*
|
||||
`MSET <MsetCommand.html>`_
|
||||
*key1* *value1* *key2* *value2* ... *keyN* *valueN*
|
||||
Set multiple keys to multiple values in a single atomic operation
|
||||
`MSETNX <MsetCommand.html>`_
|
||||
*key1* *value1* *key2* *value2* ... *keyN* *valueN*
|
||||
Set multiple keys to multiple values in a single atomic operation
|
||||
if none of the keys already exist
|
||||
`MGET <MgetCommand.html>`_
|
||||
*key1* *key2* ... *keyN*
|
||||
Multi-get, return the strings values of the keys
|
||||
`INCR <IncrCommand.html>`_
|
||||
*key*
|
||||
Increment the integer value of key
|
||||
`INCRBY <IncrCommand.html>`_
|
||||
*key* *integer*
|
||||
Increment the integer value of *key* by *integer*
|
||||
`DECR <IncrCommand.html>`_
|
||||
*key*
|
||||
Decrement the integer value of key
|
||||
`DECRBY <IncrCommand.html>`_
|
||||
*key* *integer*
|
||||
Decrement the integer value of *key* by *integer*
|
||||
`APPEND <AppendCommand.html>`_
|
||||
*key* *value*
|
||||
Append the specified string to the string stored at key
|
||||
`SUBSTR <SubstrCommand.html>`_
|
||||
*key* *start* *end*
|
||||
Return a substring of a larger string
|
||||
Commands operating on lists
|
||||
---------------------------
|
||||
|
||||
**Command**
|
||||
**Parameters**
|
||||
**Description**
|
||||
`RPUSH <RpushCommand.html>`_
|
||||
*key* *value*
|
||||
Append an element to the tail of the List value at key
|
||||
`LPUSH <RpushCommand.html>`_
|
||||
*key* *value*
|
||||
Append an element to the head of the List value at key
|
||||
`LLEN <LlenCommand.html>`_
|
||||
*key*
|
||||
Return the length of the List value at key
|
||||
`LRANGE <LrangeCommand.html>`_
|
||||
*key* *start* *end*
|
||||
Return a range of elements from the List at key
|
||||
`LTRIM <LtrimCommand.html>`_
|
||||
*key* *start* *end*
|
||||
Trim the list at key to the specified range of elements
|
||||
`LINDEX <LindexCommand.html>`_
|
||||
*key* *index*
|
||||
Return the element at index position from the List at key
|
||||
`LSET <LsetCommand.html>`_
|
||||
*key* *index* *value*
|
||||
Set a new value as the element at index position of the List at key
|
||||
`LREM <LremCommand.html>`_
|
||||
*key* *count* *value*
|
||||
Remove the first-N, last-N, or all the elements matching value from
|
||||
the List at key
|
||||
`LPOP <LpopCommand.html>`_
|
||||
*key*
|
||||
Return and remove (atomically) the first element of the List at key
|
||||
`RPOP <LpopCommand.html>`_
|
||||
*key*
|
||||
Return and remove (atomically) the last element of the List at key
|
||||
`BLPOP <BlpopCommand.html>`_
|
||||
*key1* *key2* ... *keyN* *timeout*
|
||||
Blocking LPOP
|
||||
`BRPOP <BlpopCommand.html>`_
|
||||
*key1* *key2* ... *keyN* *timeout*
|
||||
Blocking RPOP
|
||||
`RPOPLPUSH <RpoplpushCommand.html>`_
|
||||
*srckey* *dstkey*
|
||||
Return and remove (atomically) the last element of the source List
|
||||
stored at *srckey* and push the same element to the destination
|
||||
List stored at *dstkey*
|
||||
`BRPOPLPUSH <BrpoplpushCommand.html>`_
|
||||
*srckey* *dstkey*
|
||||
Like RPOPLPUSH but blocking of source key is empty
|
||||
Commands operating on sets
|
||||
--------------------------
|
||||
|
||||
**Command**
|
||||
**Parameters**
|
||||
**Description**
|
||||
`SADD <SaddCommand.html>`_
|
||||
*key* *member*
|
||||
Add the specified member to the Set value at key
|
||||
`SREM <SremCommand.html>`_
|
||||
*key* *member*
|
||||
Remove the specified member from the Set value at key
|
||||
`SPOP <SpopCommand.html>`_
|
||||
*key*
|
||||
Remove and return (pop) a random element from the Set value at key
|
||||
`SMOVE <SmoveCommand.html>`_
|
||||
*srckey* *dstkey* *member*
|
||||
Move the specified member from one Set to another atomically
|
||||
`SCARD <ScardCommand.html>`_
|
||||
*key*
|
||||
Return the number of elements (the cardinality) of the Set at key
|
||||
`SISMEMBER <SismemberCommand.html>`_
|
||||
*key* *member*
|
||||
Test if the specified value is a member of the Set at key
|
||||
`SINTER <SinterCommand.html>`_
|
||||
*key1* *key2* ... *keyN*
|
||||
Return the intersection between the Sets stored at key1, key2, ...,
|
||||
keyN
|
||||
`SINTERSTORE <SinterstoreCommand.html>`_
|
||||
*dstkey* *key1* *key2* ... *keyN*
|
||||
Compute the intersection between the Sets stored at key1, key2,
|
||||
..., keyN, and store the resulting Set at dstkey
|
||||
`SUNION <SunionCommand.html>`_
|
||||
*key1* *key2* ... *keyN*
|
||||
Return the union between the Sets stored at key1, key2, ..., keyN
|
||||
`SUNIONSTORE <SunionstoreCommand.html>`_
|
||||
*dstkey* *key1* *key2* ... *keyN*
|
||||
Compute the union between the Sets stored at key1, key2, ..., keyN,
|
||||
and store the resulting Set at dstkey
|
||||
`SDIFF <SdiffCommand.html>`_
|
||||
*key1* *key2* ... *keyN*
|
||||
Return the difference between the Set stored at key1 and all the
|
||||
Sets key2, ..., keyN
|
||||
`SDIFFSTORE <SdiffstoreCommand.html>`_
|
||||
*dstkey* *key1* *key2* ... *keyN*
|
||||
Compute the difference between the Set key1 and all the Sets key2,
|
||||
..., keyN, and store the resulting Set at dstkey
|
||||
`SMEMBERS <SmembersCommand.html>`_
|
||||
*key*
|
||||
Return all the members of the Set value at key
|
||||
`SRANDMEMBER <SrandmemberCommand.html>`_
|
||||
*key*
|
||||
Return a random member of the Set value at key
|
||||
Commands operating on sorted zsets (sorted sets)
|
||||
------------------------------------------------
|
||||
|
||||
**Command**
|
||||
**Parameters**
|
||||
**Description**
|
||||
`ZADD <ZaddCommand.html>`_
|
||||
*key* *score* *member*
|
||||
Add the specified member to the Sorted Set value at key or update
|
||||
the score if it already exist
|
||||
`ZREM <ZremCommand.html>`_
|
||||
*key* *member*
|
||||
Remove the specified member from the Sorted Set value at key
|
||||
`ZINCRBY <ZincrbyCommand.html>`_
|
||||
*key* *increment* *member*
|
||||
If the member already exists increment its score by *increment*,
|
||||
otherwise add the member setting *increment* as score
|
||||
`ZRANK <ZrankCommand.html>`_
|
||||
*key* *member*
|
||||
Return the rank (or index) or *member* in the sorted set at *key*,
|
||||
with scores being ordered from low to high
|
||||
`ZREVRANK <ZrankCommand.html>`_
|
||||
*key* *member*
|
||||
Return the rank (or index) or *member* in the sorted set at *key*,
|
||||
with scores being ordered from high to low
|
||||
`ZRANGE <ZrangeCommand.html>`_
|
||||
*key* *start* *end*
|
||||
Return a range of elements from the sorted set at key
|
||||
`ZREVRANGE <ZrangeCommand.html>`_
|
||||
*key* *start* *end*
|
||||
Return a range of elements from the sorted set at key, exactly like
|
||||
ZRANGE, but the sorted set is ordered in traversed in reverse
|
||||
order, from the greatest to the smallest score
|
||||
`ZRANGEBYSCORE <ZrangebyscoreCommand.html>`_
|
||||
*key* *min* *max*
|
||||
Return all the elements with score >= min and score <= max (a range
|
||||
query) from the sorted set
|
||||
`ZCOUNT <ZrangebyscoreCommand.html>`_
|
||||
*key* *min* *max*
|
||||
Return the number of elements with score >= min and score <= max in
|
||||
the sorted set
|
||||
`ZCARD <ZcardCommand.html>`_
|
||||
*key*
|
||||
Return the cardinality (number of elements) of the sorted set at
|
||||
key
|
||||
`ZSCORE <ZscoreCommand.html>`_
|
||||
*key* *element*
|
||||
Return the score associated with the specified element of the
|
||||
sorted set at key
|
||||
`ZREMRANGEBYRANK <ZremrangebyrankCommand.html>`_
|
||||
*key* *min* *max*
|
||||
Remove all the elements with rank >= min and rank <= max from the
|
||||
sorted set
|
||||
`ZREMRANGEBYSCORE <ZremrangebyscoreCommand.html>`_
|
||||
*key* *min* *max*
|
||||
Remove all the elements with score >= min and score <= max from the
|
||||
sorted set
|
||||
`ZUNIONSTORE / ZINTERSTORE <ZunionstoreCommand.html>`_
|
||||
*dstkey* *N* *key1* ... *keyN* WEIGHTS *w1* ... *wN* AGGREGATE
|
||||
SUM\|MIN\|MAX
|
||||
Perform a union or intersection over a number of sorted sets with
|
||||
optional weight and aggregate
|
||||
Commands operating on hashes
|
||||
----------------------------
|
||||
|
||||
**Command**
|
||||
**Parameters**
|
||||
**Description**
|
||||
`HSET <HsetCommand.html>`_
|
||||
*key* *field* *value*
|
||||
Set the hash field to the specified value. Creates the hash if
|
||||
needed.
|
||||
`HGET <HgetCommand.html>`_
|
||||
*key* *field*
|
||||
Retrieve the value of the specified hash field.
|
||||
`HMGET <HmgetCommand.html>`_
|
||||
*key* *field1* ... *fieldN*
|
||||
Get the hash values associated to the specified fields.
|
||||
`HMSET <HmsetCommand.html>`_
|
||||
*key* *field1* *value1* ... *fieldN* *valueN*
|
||||
Set the hash fields to their respective values.
|
||||
`HINCRBY <HincrbyCommand.html>`_
|
||||
*key* *field* *integer*
|
||||
Increment the integer value of the hash at *key* on *field* with
|
||||
*integer*.
|
||||
`HEXISTS <HexistsCommand.html>`_
|
||||
*key* *field*
|
||||
Test for existence of a specified field in a hash
|
||||
`HDEL <HdelCommand.html>`_
|
||||
*key* *field*
|
||||
Remove the specified field from a hash
|
||||
`HLEN <HlenCommand.html>`_
|
||||
*key*
|
||||
Return the number of items in a hash.
|
||||
`HKEYS <HgetallCommand.html>`_
|
||||
*key*
|
||||
Return all the fields in a hash.
|
||||
`HVALS <HgetallCommand.html>`_
|
||||
*key*
|
||||
Return all the values in a hash.
|
||||
`HGETALL <HgetallCommand.html>`_
|
||||
*key*
|
||||
Return all the fields and associated values in a hash.
|
||||
Sorting
|
||||
-------
|
||||
|
||||
**Command**
|
||||
**Parameters**
|
||||
**Description**
|
||||
`SORT <SortCommand.html>`_
|
||||
*key* BY *pattern* LIMIT *start* *end* GET *pattern* ASC\|DESC
|
||||
ALPHA
|
||||
Sort a Set or a List accordingly to the specified parameters
|
||||
Transactions
|
||||
------------
|
||||
|
||||
**Command**
|
||||
**Parameters**
|
||||
**Description**
|
||||
`MULTI/EXEC/DISCARD/WATCH/UNWATCH <MultiExecCommand.html>`_
|
||||
-
|
||||
Redis atomic transactions
|
||||
Publish/Subscribe
|
||||
-----------------
|
||||
|
||||
**Command**
|
||||
**Parameters**
|
||||
**Description**
|
||||
`SUBSCRIBE/UNSUBSCRIBE/PUBLISH <PublishSubscribe.html>`_
|
||||
-
|
||||
Redis Public/Subscribe messaging paradigm implementation
|
||||
Persistence control commands
|
||||
----------------------------
|
||||
|
||||
**Command**
|
||||
**Parameters**
|
||||
**Description**
|
||||
`SAVE <SaveCommand.html>`_
|
||||
-
|
||||
Synchronously save the DB on disk
|
||||
`BGSAVE <BgsaveCommand.html>`_
|
||||
-
|
||||
Asynchronously save the DB on disk
|
||||
`LASTSAVE <LastsaveCommand.html>`_
|
||||
-
|
||||
Return the UNIX time stamp of the last successfully saving of the
|
||||
dataset on disk
|
||||
`SHUTDOWN <ShutdownCommand.html>`_
|
||||
-
|
||||
Synchronously save the DB on disk, then shutdown the server
|
||||
`BGREWRITEAOF <BgrewriteaofCommand.html>`_
|
||||
-
|
||||
Rewrite the append only file in background when it gets too big
|
||||
Remote server control commands
|
||||
------------------------------
|
||||
|
||||
**Command**
|
||||
**Parameters**
|
||||
**Description**
|
||||
`INFO <InfoCommand.html>`_
|
||||
-
|
||||
Provide information and statistics about the server
|
||||
`MONITOR <MonitorCommand.html>`_
|
||||
-
|
||||
Dump all the received requests in real time
|
||||
`SLAVEOF <SlaveofCommand.html>`_
|
||||
-
|
||||
Change the replication settings
|
||||
`CONFIG <ConfigCommand.html>`_
|
||||
-
|
||||
Configure a Redis server at runtime
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,80 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**Comparisons: Contents**
|
||||
`Memcached <#Memcached>`_
|
||||
`Tokyo Cabinet / Toyo Tyrant <#Tokyo%20Cabinet%20/%20Toyo%20Tyrant>`_
|
||||
Comparisons
|
||||
===========
|
||||
|
||||
if your are asking yourself how is Redis different fom other
|
||||
key-value stores here you will find it compared to some of the most
|
||||
popular contendors (all great software) in this category.
|
||||
Memcached
|
||||
---------
|
||||
|
||||
|
||||
- Memcached is not persistent, it just holds everything in memory
|
||||
without saving since its main goal is to be used as a cache, while
|
||||
Redis is `persistent <Persistence.html>`_.
|
||||
|
||||
|
||||
- Like memcached Redis uses a key-value model, but while keys can
|
||||
just be strings, values in Redis can be `Lists <Lists.html>`_,
|
||||
`Sets <Sets.html>`_ or `SortedSets <SortedSets.html>`_ and complex
|
||||
operations like intersections, set/get n-th element of lists,
|
||||
pop/push of elements, can be performed against sets and lists.
|
||||
|
||||
Tokyo Cabinet / Toyo Tyrant
|
||||
---------------------------
|
||||
|
||||
Redis and Tokyo Cabinet can be used for the same applications, but
|
||||
actually they are *very different* beasts. If you read Twitter
|
||||
messages of people involved in scalable things both products are
|
||||
reported to work well, but surely there are times where one or the
|
||||
other can be the best choice.
|
||||
|
||||
- Tokyo Cabinet writes synchronously on disk, Redis takes the
|
||||
whole dataset on memory and writes on disk asynchronously. Tokyo
|
||||
Cabinet is safer and probably a better idea if your dataset is
|
||||
going to be bigger than RAM, but Redis is faster (note that Redis
|
||||
supports master-slave replication that is trivial to setup, so you
|
||||
are safe anyway if you want a setup where data can't be lost even
|
||||
after a disaster).
|
||||
|
||||
|
||||
- Redis supports higher level operations and data structures.
|
||||
Tokyo Cabinet supports a kind of database that is able to organize
|
||||
data into rows with named fields (in a way very similar to Berkeley
|
||||
DB) but can't do things like server side List and Set operations
|
||||
Redis is able to do: pushing or popping from Lists in an atomic
|
||||
way, in O(1) time complexity, server side Set intersections,
|
||||
Sorting of schema free data in complex ways (By the way TC supports
|
||||
sorting in the table-based database format). Redis on the other
|
||||
hand does not support the abstraction of tables with fields, the
|
||||
idea is that you can build this stuff in software easily if you
|
||||
really need a table-alike approach.
|
||||
|
||||
|
||||
- Tokyo Cabinet does not implement a networking layer. You have to
|
||||
use a networking layer called Tokyo Tyrant that interfaces to Tokyo
|
||||
Cabinet so you can talk to Tokyo Cabinet in a client-server
|
||||
fashion. In Redis the networking support is built-in inside the
|
||||
server, and is basically the only interface between the external
|
||||
world and the dataset.
|
||||
|
||||
|
||||
- Redis is reported to be much faster, especially if you plan to
|
||||
access Tokyo Cabinet via Tokyo Tyrant. Here I can only say that
|
||||
with Redis you can expect 100,000 operations/seconds with a normal
|
||||
Linux box and 50 concurrent clients. You should test Redis, Tokyo,
|
||||
and the other alternatives with your specific work load to get a
|
||||
feeling about performances for your application.
|
||||
|
||||
|
||||
- Redis is not an on-disk DB engine like Tokyo: the latter can be
|
||||
used as a fast DB engine in your C project without the networking
|
||||
overhead just linking to the library. Still in many scalable
|
||||
applications you need multiple servers talking with multiple
|
||||
clients, so the client-server model is almost always needed, this
|
||||
is why in Redis this is built-in.
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,115 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**ConfigCommand: Contents**
|
||||
`CONFIG GET \_pattern\_ (Redis > <#CONFIG%20GET%20_pattern_%20(Redis%20%3E>`_
|
||||
`CONFIG SET \_parameter\_ \_value\_ (Redis > <#CONFIG%20SET%20_parameter_%20_value_%20(Redis%20%3E>`_
|
||||
`CONFIG GET \_pattern\_ <#CONFIG%20GET%20_pattern_>`_
|
||||
`CONFIG SET \_parameter\_ \_value\_ <#CONFIG%20SET%20_parameter_%20_value_>`_
|
||||
`Parameters value format <#Parameters%20value%20format>`_
|
||||
`See Also <#See%20Also>`_
|
||||
ConfigCommand
|
||||
=============
|
||||
|
||||
#sidebar `ControlCommandsSidebar <ControlCommandsSidebar.html>`_
|
||||
CONFIG GET \_pattern\_ (Redis >
|
||||
===============================
|
||||
|
||||
2.0)=
|
||||
CONFIG SET \_parameter\_ \_value\_ (Redis >
|
||||
===========================================
|
||||
|
||||
2.0)=
|
||||
The CONFIG command is able to retrieve or alter the configuration
|
||||
of a runningRedis server. Not all the configuration parameters are
|
||||
supported.
|
||||
|
||||
CONFIG has two sub commands, GET and SET. The GET command is used
|
||||
to readthe configuration, while the SET command is used to alter
|
||||
the configuration.
|
||||
|
||||
CONFIG GET \_pattern\_
|
||||
----------------------
|
||||
|
||||
CONFIG GET returns the current configuration parameters. This sub
|
||||
commandonly accepts a single argument, that is glob style pattern.
|
||||
All theconfiguration parameters matching this parameter are
|
||||
reported as alist of key-value pairs. Example:
|
||||
|
||||
::
|
||||
|
||||
$ redis-cli config get '*'
|
||||
1. "dbfilename"
|
||||
2. "dump.rdb"
|
||||
3. "requirepass"
|
||||
4. (nil)
|
||||
5. "masterauth"
|
||||
6. (nil)
|
||||
7. "maxmemory"
|
||||
8. "0\n"
|
||||
9. "appendfsync"
|
||||
10. "everysec"
|
||||
11. "save"
|
||||
12. "3600 1 300 100 60 10000"
|
||||
|
||||
$ redis-cli config get 'm*'
|
||||
1. "masterauth"
|
||||
2. (nil)
|
||||
3. "maxmemory"
|
||||
4. "0\n"
|
||||
|
||||
The return type of the command is a
|
||||
`bulk reply <ReplyTypes.html>`_.
|
||||
CONFIG SET \_parameter\_ \_value\_
|
||||
----------------------------------
|
||||
|
||||
CONFIG SET is used in order to reconfigure the server, setting a
|
||||
specificconfiguration parameter to a new value.
|
||||
|
||||
The list of configuration parameters supported by CONFIG SET can
|
||||
beobtained issuing a ``CONFIG GET *`` command.
|
||||
|
||||
The configuration set using CONFIG SET is immediately loaded by the
|
||||
Redisserver that will start acting as specified starting from the
|
||||
next command.
|
||||
|
||||
Example:
|
||||
|
||||
::
|
||||
|
||||
$ ./redis-cli
|
||||
redis> set x 10
|
||||
OK
|
||||
redis> config set maxmemory 200
|
||||
OK
|
||||
redis> set y 20
|
||||
(error) ERR command not allowed when used memory > 'maxmemory'
|
||||
redis> config set maxmemory 0
|
||||
OK
|
||||
redis> set y 20
|
||||
OK
|
||||
|
||||
Parameters value format
|
||||
-----------------------
|
||||
|
||||
The value of the configuration parameter is the same as the one of
|
||||
thesame parameter in the Redis configuration file, with the
|
||||
following exceptions:
|
||||
|
||||
|
||||
- The ``save`` paramter is a list of space-separated integers.
|
||||
Every pair of integers specify the time and number of changes limit
|
||||
to trigger a save. For instance the command
|
||||
``CONFIG SET save "3600 10 60 10000"`` will configure the server to
|
||||
issue a background saving of the RDB file every 3600 seconds if
|
||||
there are at least 10 changes in the dataset, and every 60 seconds
|
||||
if there are at least 10000 changes. To completely disable
|
||||
automatic snapshots just set the parameter as an empty string.
|
||||
- All the integer parameters representing memory are returned and
|
||||
accepted only using bytes as unit.
|
||||
|
||||
See Also
|
||||
--------
|
||||
|
||||
The `INFO <InfoCommand.html>`_ command can be used in order to read
|
||||
configuriaton parameters that are not available in the CONFIG
|
||||
command.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,16 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**Configuration: Contents**
|
||||
Configuration
|
||||
=============
|
||||
|
||||
The ``redis.conf`` file included in the source code distribution is
|
||||
a starting point, you should be able to modify it in order do adapt
|
||||
it to your needs without troubles reading the comments inside the
|
||||
file.
|
||||
In order to start Redis using a configuration file just pass the
|
||||
file name as the sole argument when starting the server:
|
||||
::
|
||||
|
||||
$ ./redis-server redis.conf
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,11 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**ConnectionHandlingSidebar: Contents**
|
||||
ConnectionHandlingSidebar
|
||||
=========================
|
||||
|
||||
== Connection handling ==
|
||||
|
||||
- `QUIT <QuitCommand.html>`_
|
||||
- `AUTH <AuthCommand.html>`_
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,17 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**ControlCommandsSidebar: Contents**
|
||||
ControlCommandsSidebar
|
||||
======================
|
||||
|
||||
== Control Commands ==
|
||||
|
||||
- `SAVE <SaveCommand.html>`_
|
||||
- `BGSAVE <BgsaveCommand.html>`_
|
||||
- `BGREWRITEAOF <BgrewriteaofCommand.html>`_
|
||||
- `LASTSAVE <LastsaveCommand.html>`_
|
||||
- `SHUTDOWN <ShutdownCommand.html>`_
|
||||
- `INFO <InfoCommand.html>`_
|
||||
- `MONITOR <MonitorCommand.html>`_
|
||||
- `SLAVEOF <SlaveofCommand.html>`_
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,40 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**Credits: Contents**
|
||||
`Credits <#Credits>`_
|
||||
Credits
|
||||
=======
|
||||
|
||||
Credits
|
||||
=======
|
||||
|
||||
|
||||
- The Redis server was designed and written by
|
||||
`Salvatore Sanfilippo (aka antirez) <http://invece.org>`_
|
||||
- `Ezra Zygmuntowicz (aka ezmobius) <http://brainspl.at/>`_ - Ruby
|
||||
client lib initial version and hacking
|
||||
- `Ludovico Magnocavallo (aka ludo) <http://qix.it>`_ - Python
|
||||
clinet lib
|
||||
- `Valentino Volonghi of Adroll <http://www.adroll.com/>`_ -
|
||||
Erlang client lib
|
||||
- **brettbender** - found and fixed a bug in sds.c that caused the
|
||||
server to crash at least on 64 bit systems, and anyway to be buggy
|
||||
since we used the same vararg thing against vsprintf without to
|
||||
call va\_start and va\_end every time.
|
||||
- `Dobrica Pavlinusic <http://www.rot13.org/~dpavlin>`_ - Perl
|
||||
client lib
|
||||
- Brian Hammond - AUTH command implementation, C++ client lib
|
||||
- `Daniele Alessandri <http://www.clorophilla.net/>`_ - Lua client
|
||||
lib
|
||||
- Corey Stup - C99 cleanups
|
||||
- Taylor Weibley - Ruby client improvements
|
||||
- Bob Potter - Rearrange redisObject struct to reduce memory usage
|
||||
in 64bit environments
|
||||
- Luca Guidi and Brian McKinney - Ruby client improvements
|
||||
- Aman Gupta - SDIFF / SDIFFSTORE, other Set operations
|
||||
improvements, ability to disable clients timeout.
|
||||
- Diego Rosario Brogna - Code and ideas about dumping backtrace on
|
||||
sigsegv and similar error conditions.
|
||||
|
||||
p.s. sorry to take this file in sync is hard in this early days.
|
||||
Please drop me an email if I forgot to add your name here!
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,18 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**DbsizeCommand: Contents**
|
||||
`DBSIZE <#DBSIZE>`_
|
||||
`Return value <#Return%20value>`_
|
||||
DbsizeCommand
|
||||
=============
|
||||
|
||||
#sidebar `GenericCommandsSidebar <GenericCommandsSidebar.html>`_
|
||||
DBSIZE
|
||||
======
|
||||
|
||||
Return the number of keys in the currently selected database.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Integer reply <ReplyTypes.html>`_
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,26 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**DelCommand: Contents**
|
||||
`DEL \_key1\_ \_key2\_ ... \_keyN\_ <#DEL%20_key1_%20_key2_%20...%20_keyN_>`_
|
||||
`Return value <#Return%20value>`_
|
||||
DelCommand
|
||||
==========
|
||||
|
||||
#sidebar `GenericCommandsSidebar <GenericCommandsSidebar.html>`_
|
||||
DEL \_key1\_ \_key2\_ ... \_keyN\_
|
||||
==================================
|
||||
|
||||
*Time complexity: O(1)*
|
||||
Remove the specified keys. If a given key does not existno
|
||||
operation is performed for this key. The command returns the number
|
||||
ofkeys removed.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Integer reply <ReplyTypes.html>`_, specifically:
|
||||
::
|
||||
|
||||
an integer greater than 0 if one or more keys were removed
|
||||
0 if none of the specified key existed
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,9 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**DesignPatterns: Contents**
|
||||
DesignPatterns
|
||||
==============
|
||||
|
||||
Use random keys instead of incremental keys in order to avoid a
|
||||
single-key that gets incremented by many servers. This can can't be
|
||||
distributed among servers.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,39 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**EventLibray: Contents**
|
||||
`Event Library <#Event%20Library>`_
|
||||
`Why is an Event Library needed at all? <#Why%20is%20an%20Event%20Library%20needed%20at%20all?>`_
|
||||
EventLibray
|
||||
===========
|
||||
|
||||
Event Library
|
||||
=============
|
||||
|
||||
Why is an Event Library needed at all?
|
||||
--------------------------------------
|
||||
|
||||
Let us figure it out through a series of Q&As.
|
||||
Q: What do you expect a network server to be doing all the time?
|
||||
<br/> A: Watch for inbound connections on the port its listening
|
||||
and accept them.
|
||||
Q: Calling `accept <http://man.cx/accept(2)>`_ yields a descriptor.
|
||||
What do I do with it?<br/> A: Save the descriptor and do a
|
||||
non-blocking read/write operation on it.
|
||||
Q: Why does the read/write have to be non-blocking?<br/> A: If the
|
||||
file operation ( even a socket in Unix is a file ) is blocking how
|
||||
could the server for example accept other connection requests when
|
||||
its blocked in a file I/O operation.
|
||||
Q: I guess I have to do many such non-blocking operations on the
|
||||
socket to see when it's ready. Am I right?<br/> A: Yes. That is
|
||||
what an event library does for you. Now you get it.
|
||||
Q: How do Event Libraries do what they do?<br/> A: They use the
|
||||
operating system's
|
||||
`polling <http://www.devshed.com/c/a/BrainDump/Linux-Files-and-the-Event-Poll-Interface/>`_
|
||||
facility along with timers.
|
||||
Q: So are there any open source event libraries that do what you
|
||||
just described? <br/> A: Yes. Libevent and Libev are two such event
|
||||
libraries that I can recall off the top of my head.
|
||||
Q: Does Redis use such open source event libraries for handling
|
||||
socket I/O?<br/> A: No. For various
|
||||
`reasons <http://groups.google.com/group/redis-db/browse_thread/thread/b52814e9ef15b8d0/>`_
|
||||
Redis uses its own event library.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,26 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**ExistsCommand: Contents**
|
||||
`EXISTS \_key\_ <#EXISTS%20_key_>`_
|
||||
`Return value <#Return%20value>`_
|
||||
ExistsCommand
|
||||
=============
|
||||
|
||||
#sidebar `GenericCommandsSidebar <GenericCommandsSidebar.html>`_
|
||||
EXISTS \_key\_
|
||||
==============
|
||||
|
||||
*Time complexity: O(1)*
|
||||
Test if the specified key exists. The command returns"0" if the key
|
||||
exists, otherwise "1" is returned.Note that even keys set with an
|
||||
empty string as value willreturn "1".
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Integer reply <ReplyTypes.html>`_, specifically:
|
||||
::
|
||||
|
||||
1 if the key exists.
|
||||
0 if the key does not exist.
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,238 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**ExpireCommand: Contents**
|
||||
`EXPIRE \_key\_ \_seconds\_ <#EXPIRE%20_key_%20_seconds_>`_
|
||||
`EXPIREAT \_key\_ \_unixtime\_ (Redis > <#EXPIREAT%20_key_%20_unixtime_%20(Redis%20%3E>`_
|
||||
`PERSIST \_key\_ (Redis > <#PERSIST%20_key_%20(Redis%20%3E>`_
|
||||
`How the expire is removed from a key <#How%20the%20expire%20is%20removed%20from%20a%20key>`_
|
||||
`Restrictions with write operations against volatile keys <#Restrictions%20with%20write%20operations%20against%20volatile%20keys>`_
|
||||
`Restrictions for write operations with volatile keys as sources <#Restrictions%20for%20write%20operations%20with%20volatile%20keys%20as%20sources>`_
|
||||
`Setting the timeout again on already volatile keys <#Setting%20the%20timeout%20again%20on%20already%20volatile%20keys>`_
|
||||
`Enhanced Lazy Expiration algorithm <#Enhanced%20Lazy%20Expiration%20algorithm>`_
|
||||
`Version 1.0 <#Version%201.0>`_
|
||||
`Version 1.1 <#Version%201.1>`_
|
||||
`Return value <#Return%20value>`_
|
||||
`FAQ: Can you explain better why Redis < 2.1.3 deletes keys with an EXPIRE on write operations? <#FAQ:%20Can%20you%20explain%20better%20why%20Redis%20%3C%202.1.3%20deletes%20keys%20with%20an%20EXPIRE%20on%20write%20operations?>`_
|
||||
`FAQ: How this limitations were solved in Redis versions > 2.1.3? <#FAQ:%20How%20this%20limitations%20were%20solved%20in%20Redis%20versions%20%3E%202.1.3?>`_
|
||||
ExpireCommand
|
||||
=============
|
||||
|
||||
#sidebar `GenericCommandsSidebar <GenericCommandsSidebar.html>`_
|
||||
EXPIRE \_key\_ \_seconds\_
|
||||
==========================
|
||||
|
||||
EXPIREAT \_key\_ \_unixtime\_ (Redis >
|
||||
======================================
|
||||
|
||||
1.1)=
|
||||
PERSIST \_key\_ (Redis >
|
||||
========================
|
||||
|
||||
2.1.3) = *Time complexity: O(1)*
|
||||
Set a timeout on the specified key. After the timeout the key will
|
||||
beautomatically deleted by the server. A key with an associated
|
||||
timeout issaid to be *volatile* in Redis terminology.
|
||||
|
||||
Voltile keys are stored on disk like the other keys, the timeout is
|
||||
persistenttoo like all the other aspects of the dataset. Saving a
|
||||
dataset containingexpires and stopping the server does not stop the
|
||||
flow of time as Redisstores on disk the time when the key will no
|
||||
longer be available as Unixtime, and not the remaining seconds.
|
||||
|
||||
EXPIREAT works exctly like EXPIRE but instead to get the number of
|
||||
secondsrepresenting the Time To Live of the key as a second
|
||||
argument (that is arelative way of specifing the TTL), it takes an
|
||||
absolute one in the form ofa UNIX timestamp (Number of seconds
|
||||
elapsed since 1 Gen 1970).
|
||||
|
||||
EXPIREAT was introduced in order to implement
|
||||
`the Append Only File persistence mode <AppendOnlyFileHowto.html>`_so
|
||||
that EXPIRE commands are automatically translated into EXPIREAT
|
||||
commands for the append only file. Of course EXPIREAT can alsoused
|
||||
by programmers that need a way to simply specify that a given key
|
||||
should expire at a given time in the future.
|
||||
|
||||
Since Redis 2.1.3 you can update the value of the timeout of a key
|
||||
alreadyhaving an expire set. It is also possible to undo the expire
|
||||
at allturning the key into a normal key using the PERSIST command.
|
||||
|
||||
How the expire is removed from a key
|
||||
------------------------------------
|
||||
|
||||
When the key is set to a new value using the SET command, or when a
|
||||
keyis destroied via DEL, the timeout is removed from the key.
|
||||
|
||||
Restrictions with write operations against volatile keys
|
||||
--------------------------------------------------------
|
||||
|
||||
IMPORTANT: Since Redis 2.1.3 or greater, there are no restrictions
|
||||
aboutthe operations you can perform against volatile keys, however
|
||||
older versionsof Redis, including the current stable version 2.0.0,
|
||||
has the followinglimitations:
|
||||
|
||||
Write operations like LPUSH, LSET and every other command that has
|
||||
theeffect of modifying the value stored at a volatile key have a
|
||||
special semantic:basically a volatile key is destroyed when it is
|
||||
target of a write operation.See for example the following usage
|
||||
pattern:
|
||||
|
||||
::
|
||||
|
||||
% ./redis-cli lpush mylist foobar /Users/antirez/hack/redis
|
||||
OK
|
||||
% ./redis-cli lpush mylist hello /Users/antirez/hack/redis
|
||||
OK
|
||||
% ./redis-cli expire mylist 10000 /Users/antirez/hack/redis
|
||||
1
|
||||
% ./redis-cli lpush mylist newelement
|
||||
OK
|
||||
% ./redis-cli lrange mylist 0 -1 /Users/antirez/hack/redis
|
||||
1. newelement
|
||||
|
||||
What happened here is that LPUSH against the key with a timeout set
|
||||
deletedthe key before to perform the operation. There is so a
|
||||
simple rule, writeoperations against volatile keys will destroy the
|
||||
key before to perform theoperation. Why Redis uses this behavior?
|
||||
In order to retain an importantproperty: a server that receives a
|
||||
given number of commands in the samesequence will end with the same
|
||||
dataset in memory. Without the delete-on-writesemantic what happens
|
||||
is that the state of the server depends on the timethe commands
|
||||
were issued. This is not a desirable property in a distributed
|
||||
databasethat supports replication.
|
||||
|
||||
Restrictions for write operations with volatile keys as sources
|
||||
---------------------------------------------------------------
|
||||
|
||||
Even when the volatile key is not modified as part of a write
|
||||
operation, if it is read in a composite write operation (such as
|
||||
SINTERSTORE) it will be cleared at the start of the operation. This
|
||||
is done to avoid concurrency issues in replication. Imagine a key
|
||||
that is about to expire and the composite operation is run against
|
||||
it. On a slave node, this key might already be expired, which
|
||||
leaves you with a desync in your dataset.
|
||||
Setting the timeout again on already volatile keys
|
||||
--------------------------------------------------
|
||||
|
||||
Trying to call EXPIRE against a key that already has an associated
|
||||
timeoutwill not change the timeout of the key, but will just return
|
||||
0. If insteadthe key does not have a timeout associated the timeout
|
||||
will be set and EXPIREwill return 1.
|
||||
|
||||
Enhanced Lazy Expiration algorithm
|
||||
----------------------------------
|
||||
|
||||
Redis does not constantly monitor keys that are going to be
|
||||
expired.Keys are expired simply when some client tries to access a
|
||||
key, andthe key is found to be timed out.
|
||||
|
||||
Of course this is not enough as there are expired keys that will
|
||||
neverbe accessed again. This keys should be expired anyway, so once
|
||||
everysecond Redis test a few keys at random among keys with an
|
||||
expire set.All the keys that are already expired are deleted from
|
||||
the keyspace.
|
||||
|
||||
Version 1.0
|
||||
~~~~~~~~~~~
|
||||
|
||||
Each time a fixed number of keys where tested (100 by default). So
|
||||
ifyou had a client setting keys with a very short expire faster
|
||||
than 100for second the memory continued to grow. When you stopped
|
||||
to insertnew keys the memory started to be freed, 100 keys every
|
||||
second in thebest conditions. Under a peak Redis continues to use
|
||||
more and more RAMeven if most keys are expired in each sweep.
|
||||
|
||||
Version 1.1
|
||||
~~~~~~~~~~~
|
||||
|
||||
Each time Redis:
|
||||
|
||||
|
||||
#. Tests 100 random keys from expired keys set.
|
||||
#. Deletes all the keys found expired.
|
||||
#. If more than 25 keys were expired, it start again from 1.
|
||||
|
||||
This is a trivial probabilistic algorithm, basically the assumption
|
||||
isthat our sample is representative of the whole key space,and we
|
||||
continue to expire until the percentage of keys that are likelyto
|
||||
be expired is under 25%
|
||||
|
||||
This means that at any given moment the maximum amount of keys
|
||||
alreadyexpired that are using memory is at max equal to max setting
|
||||
operations per second divided by 4.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Integer reply <ReplyTypes.html>`_, specifically:
|
||||
::
|
||||
|
||||
1: the timeout was set.
|
||||
0: the timeout was not set since the key already has an associated timeout
|
||||
(this may happen only in Redis versions < 2.1.3, Redis >= 2.1.3 will
|
||||
happily update the timeout), or the key does not exist.
|
||||
|
||||
FAQ: Can you explain better why Redis < 2.1.3 deletes keys with an EXPIRE on write operations?
|
||||
----------------------------------------------------------------------------------------------
|
||||
|
||||
Ok let's start with the problem:
|
||||
::
|
||||
|
||||
redis> set a 100
|
||||
OK
|
||||
redis> expire a 360
|
||||
(integer) 1
|
||||
redis> incr a
|
||||
(integer) 1
|
||||
|
||||
I set a key to the value of 100, then set an expire of 360 seconds,
|
||||
and then incremented the key (before the 360 timeout expired of
|
||||
course). The obvious result would be: 101, instead the key is set
|
||||
to the value of 1. Why? There is a very important reason involving
|
||||
the Append Only File and Replication. Let's rework a bit our
|
||||
example adding the notion of time to the mix:
|
||||
::
|
||||
|
||||
SET a 100
|
||||
EXPIRE a 5
|
||||
... wait 10 seconds ...
|
||||
INCR a
|
||||
|
||||
Imagine a Redis version that does not implement the "Delete keys
|
||||
with an expire set on write operation" semantic. Running the above
|
||||
example with the 10 seconds pause will lead to 'a' being set to the
|
||||
value of 1, as it no longer exists when INCR is called 10 seconds
|
||||
later.
|
||||
Instead if we drop the 10 seconds pause, the result is that 'a' is
|
||||
set to 101.
|
||||
And in the practice timing changes! For instance the client may
|
||||
wait 10 seconds before INCR, but the sequence written in the Append
|
||||
Only File (and later replayed-back as fast as possible when Redis
|
||||
is restarted) will not have the pause. Even if we add a timestamp
|
||||
in the AOF, when the time difference is smaller than our timer
|
||||
resolution, we have a race condition.
|
||||
The same happens with master-slave replication. Again, consider the
|
||||
example above: the client will use the same sequence of commands
|
||||
without the 10 seconds pause, but the replication link will slow
|
||||
down for a few seconds due to a network problem. Result? The master
|
||||
will contain 'a' set to 101, the slave 'a' set to 1.
|
||||
The only way to avoid this but at the same time have reliable non
|
||||
time dependent timeouts on keys is to destroy volatile keys when a
|
||||
write operation is attempted against it.
|
||||
After all Redis is one of the rare fully persistent databases that
|
||||
will give you EXPIRE. This comes to a cost :)
|
||||
FAQ: How this limitations were solved in Redis versions > 2.1.3?
|
||||
----------------------------------------------------------------
|
||||
|
||||
Since Redis 2.1.3 there are no longer restrictions in the use you
|
||||
can do of write commands against volatile keys, still the
|
||||
replication and AOF file are guaranteed to be fully consistent.
|
||||
In order to obtain a correct behavior without sacrificing
|
||||
consistency now when a key expires, a DEL operation is synthesized
|
||||
in both the AOF file and against all the attached slaves. This way
|
||||
the expiration process is centralized in the master instance, and
|
||||
there is no longer a chance of consistency errors.
|
||||
However while the slaves while connected to a master will not
|
||||
expire keys independently, they'll still take the full state of the
|
||||
expires existing in the dataset, so when a slave is elected to a
|
||||
master it will be able to expire the keys independently, fully
|
||||
acting as a master.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,364 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**FAQ: Contents**
|
||||
`Isn't this key-value thing just hype? <#Isn't%20this%20key-value%20thing%20just%20hype?>`_
|
||||
`Can I backup a Redis DB while the server is working? <#Can%20I%20backup%20a%20Redis%20DB%20while%20the%20server%20is%20working?>`_
|
||||
`What's the Redis memory footprint? <#What's%20the%20Redis%20memory%20footprint?>`_
|
||||
`I like Redis high level operations and features, but I don't like it takes everything in memory and I can't have a dataset larger the memory. Plans to change this? <#I%20like%20Redis%20high%20level%20operations%20and%20features,%20but%20I%20don't%20like%20it%20takes%20everything%20in%20memory%20and%20I%20can't%20have%20a%20dataset%20larger%20the%20memory.%20Plans%20to%20change%20this?>`_
|
||||
`Why Redis takes the whole dataset in RAM? <#Why%20Redis%20takes%20the%20whole%20dataset%20in%20RAM?>`_
|
||||
`If my dataset is too big for RAM and I don't want to use consistent hashing or other ways to distribute the dataset across different nodes, what I can do to use Redis anyway? <#If%20my%20dataset%20is%20too%20big%20for%20RAM%20and%20I%20don't%20want%20to%20use%20consistent%20hashing%20or%20other%20ways%20to%20distribute%20the%20dataset%20across%20different%20nodes,%20what%20I%20can%20do%20to%20use%20Redis%20anyway?>`_
|
||||
`Do you plan to implement Virtual Memory in Redis? Why don't just let the Operating System handle it for you? <#Do%20you%20plan%20to%20implement%20Virtual%20Memory%20in%20Redis?%20Why%20don't%20just%20let%20the%20Operating%20System%20handle%20it%20for%20you?>`_
|
||||
`Is there something I can do to lower the Redis memory usage? <#Is%20there%20something%20I%20can%20do%20to%20lower%20the%20Redis%20memory%20usage?>`_
|
||||
`I have an empty Redis server but INFO and logs are reporting megabytes of memory in use! <#I%20have%20an%20empty%20Redis%20server%20but%20INFO%20and%20logs%20are%20reporting%20megabytes%20of%20memory%20in%20use!>`_
|
||||
`What happens if Redis runs out of memory? <#What%20happens%20if%20Redis%20runs%20out%20of%20memory?>`_
|
||||
`Does Redis use more memory running in 64 bit boxes? Can I use 32 bit Redis in 64 bit systems? <#Does%20Redis%20use%20more%20memory%20running%20in%2064%20bit%20boxes?%20Can%20I%20use%2032%20bit%20Redis%20in%2064%20bit%20systems?>`_
|
||||
`How much time it takes to load a big database at server startup? <#How%20much%20time%20it%20takes%20to%20load%20a%20big%20database%20at%20server%20startup?>`_
|
||||
`Background saving is failing with a fork() error under Linux even if I've a lot of free RAM! <#Background%20saving%20is%20failing%20with%20a%20fork()%20error%20under%20Linux%20even%20if%20I've%20a%20lot%20of%20free%20RAM!>`_
|
||||
`Are Redis on disk snapshots atomic? <#Are%20Redis%20on%20disk%20snapshots%20atomic?>`_
|
||||
`Redis is single threaded, how can I exploit multiple CPU / cores? <#Redis%20is%20single%20threaded,%20how%20can%20I%20exploit%20multiple%20CPU%20/%20cores?>`_
|
||||
`I'm using some form of key hashing for partitioning, but what about SORT BY? <#I'm%20using%20some%20form%20of%20key%20hashing%20for%20partitioning,%20but%20what%20about%20SORT%20BY?>`_
|
||||
`What is the maximum number of keys a single Redis instance can hold? and what the max number of elements in a List, Set, Ordered Set? <#What%20is%20the%20maximum%20number%20of%20keys%20a%20single%20Redis%20instance%20can%20hold?%20and%20what%20the%20max%20number%20of%20elements%20in%20a%20List,%20Set,%20Ordered%20Set?>`_
|
||||
`What Redis means actually? <#What%20Redis%20means%20actually?>`_
|
||||
`Why did you started the Redis project? <#Why%20did%20you%20started%20the%20Redis%20project?>`_
|
||||
FAQ
|
||||
===
|
||||
|
||||
= Why I need Redis if there is already memcachedb, Tokyo
|
||||
Cabinet, ...? =
|
||||
Memcachedb is basically memcached done persistent. Redis is a
|
||||
different evolution path in the key-value DBs, the idea is that the
|
||||
main advantages of key-value DBs are retained even without a so
|
||||
severe loss of comfort of plain key-value DBs. So Redis offers more
|
||||
features:
|
||||
|
||||
- Keys can store different data types, not just strings. Notably
|
||||
Lists and Sets. For example if you want to use Redis as a log
|
||||
storage system for different computers every computer can just
|
||||
``RPUSH data to the computer_ID key``. Don't want to save more than
|
||||
1000 log lines per computer? Just issue a
|
||||
``LTRIM computer_ID 0 999`` command to trim the list after every
|
||||
push.
|
||||
|
||||
|
||||
- Another example is about Sets. Imagine to build a social news
|
||||
site like `Reddit <http://reddit.com>`_. Every time a user upvote a
|
||||
given news you can just add to the news\_ID\_upmods key holding a
|
||||
value of type SET the id of the user that did the upmodding. Sets
|
||||
can also be used to index things. Every key can be a tag holding a
|
||||
SET with the IDs of all the objects associated to this tag. Using
|
||||
Redis set intersection you obtain the list of IDs having all this
|
||||
tags at the same time.
|
||||
|
||||
|
||||
- We wrote a `simple Twitter Clone <http://retwis.antirez.com>`_
|
||||
using just Redis as database. Download the source code from the
|
||||
download section and imagine to write it with a plain key-value DB
|
||||
without support for lists and sets... it's **much** harder.
|
||||
|
||||
|
||||
- Multiple DBs. Using the SELECT command the client can select
|
||||
different datasets. This is useful because Redis provides a MOVE
|
||||
atomic primitive that moves a key form a DB to another one, if the
|
||||
target DB already contains such a key it returns an error: this
|
||||
basically means a way to perform locking in distributed
|
||||
processing.
|
||||
|
||||
|
||||
- **So what is Redis really about?** The User interface with the
|
||||
programmer. Redis aims to export to the programmer the right tools
|
||||
to model a wide range of problems.
|
||||
**Sets, Lists with O(1) push operation, lrange and ltrim, server-side fast intersection between sets, are primitives that allow to model complex problems with a key value database**.
|
||||
|
||||
Isn't this key-value thing just hype?
|
||||
=====================================
|
||||
|
||||
I imagine key-value DBs, in the short term future, to be used like
|
||||
you use memory in a program, with lists, hashes, and so on. With
|
||||
Redis it's like this, but this special kind of memory containing
|
||||
your data structures is shared, atomic, persistent.
|
||||
When we write code it is obvious, when we take data in memory, to
|
||||
use the most sensible data structure for the work, right?
|
||||
Incredibly when data is put inside a relational DB this is no
|
||||
longer true, and we create an absurd data model even if our need is
|
||||
to put data and get this data back in the same order we put it
|
||||
inside (an ORDER BY is required when the data should be already
|
||||
sorted. Strange, dont' you think?).
|
||||
Key-value DBs bring this back at home, to create sensible data
|
||||
models and use the right data structures for the problem we are
|
||||
trying to solve.
|
||||
Can I backup a Redis DB while the server is working?
|
||||
====================================================
|
||||
|
||||
Yes you can. When Redis saves the DB it actually creates a temp
|
||||
file, then rename(2) that temp file name to the destination file
|
||||
name. So even while the server is working it is safe to save the
|
||||
database file just with the *cp* unix command. Note that you can
|
||||
use master-slave replication in order to have redundancy of data,
|
||||
but if all you need is backups, cp or scp will do the work pretty
|
||||
well.
|
||||
What's the Redis memory footprint?
|
||||
==================================
|
||||
|
||||
Worst case scenario: 1 Million keys with the key being the natural
|
||||
numbers from 0 to 999999 and the string "Hello World" as value use
|
||||
100MB on my Intel macbook (32bit). Note that the same data stored
|
||||
linearly in an unique string takes something like 16MB, this is the
|
||||
norm because with small keys and values there is a lot of overhead.
|
||||
Memcached will perform similarly.
|
||||
With large keys/values the ratio is much better of course.
|
||||
64 bit systems will use much more memory than 32 bit systems to
|
||||
store the same keys, especially if the keys and values are small,
|
||||
this is because pointers takes 8 bytes in 64 bit systems. But of
|
||||
course the advantage is that you can have a lot of memory in 64 bit
|
||||
systems, so to run large Redis servers a 64 bit system is more or
|
||||
less required.
|
||||
I like Redis high level operations and features, but I don't like it takes everything in memory and I can't have a dataset larger the memory. Plans to change this?
|
||||
===================================================================================================================================================================
|
||||
|
||||
Short answer: If you are using a Redis client that supports
|
||||
consistent hashing you can distribute the dataset across different
|
||||
nodes. For instance the Ruby clients supports this feature. There
|
||||
are plans to develop redis-cluster that basically is a dummy Redis
|
||||
server that is only used in order to distribute the requests among
|
||||
N different nodes using consistent hashing.
|
||||
Why Redis takes the whole dataset in RAM?
|
||||
=========================================
|
||||
|
||||
Redis takes the whole dataset in memory and writes asynchronously
|
||||
on disk in order to be very fast, you have the best of both worlds:
|
||||
hyper-speed and persistence of data, but the price to pay is
|
||||
exactly this, that the dataset must fit on your computers RAM.
|
||||
If the data is larger then memory, and this data is stored on disk,
|
||||
what happens is that the bottleneck of the disk I/O speed will
|
||||
start to ruin the performances. Maybe not in benchmarks, but once
|
||||
you have real load from multiple clients with distributed key
|
||||
accesses the data must come from disk, and the disk is damn slow.
|
||||
Not only, but Redis supports higher level data structures than the
|
||||
plain values. To implement this things on disk is even slower.
|
||||
Redis will always continue to hold the whole dataset in memory
|
||||
because this days scalability requires to use RAM as storage media,
|
||||
and RAM is getting cheaper and cheaper. Today it is common for an
|
||||
entry level server to have 16 GB of RAM! And in the 64-bit era
|
||||
there are no longer limits to the amount of RAM you can have in
|
||||
theory.
|
||||
Amazon EC2 now provides instances with 32 or 64 GB of RAM.
|
||||
If my dataset is too big for RAM and I don't want to use consistent hashing or other ways to distribute the dataset across different nodes, what I can do to use Redis anyway?
|
||||
==============================================================================================================================================================================
|
||||
|
||||
You may try to load a dataset larger than your memory in Redis and
|
||||
see what happens, basically if you are using a modern Operating
|
||||
System, and you have a lot of data in the DB that is rarely
|
||||
accessed, the OS's virtual memory implementation will try to swap
|
||||
rarely used pages of memory on the disk, to only recall this pages
|
||||
when they are needed. If you have many large values rarely used
|
||||
this will work. If your DB is big because you have tons of little
|
||||
values accessed at random without a specific pattern this will not
|
||||
work (at low level a page is usually 4096 bytes, and you can have
|
||||
different keys/values stored at a single page. The OS can't swap
|
||||
this page on disk if there are even few keys used frequently).
|
||||
Another possible solution is to use both MySQL and Redis at the
|
||||
same time, basically take the state on Redis, and all the things
|
||||
that get accessed very frequently: user auth tokens, Redis Lists
|
||||
with chronologically ordered IDs of the last N-comments, N-posts,
|
||||
and so on. Then use MySQL as a simple storage engine for larger
|
||||
data, that is just create a table with an auto-incrementing ID as
|
||||
primary key and a large BLOB field as data field. Access MySQL data
|
||||
only by primary key (the ID). The application will run the high
|
||||
traffic queries against Redis but when there is to take the big
|
||||
data will ask MySQL for specific resources IDs.
|
||||
Update: it could be interesting to test how Redis performs with
|
||||
datasets larger than memory if the OS swap partition is in one of
|
||||
this very fast Intel SSD disks.
|
||||
Do you plan to implement Virtual Memory in Redis? Why don't just let the Operating System handle it for you?
|
||||
============================================================================================================
|
||||
|
||||
Yes, in order to support datasets bigger than RAM there is the plan
|
||||
to implement transparent Virtual Memory in Redis, that is, the
|
||||
ability to transfer large values associated to keys rarely used on
|
||||
Disk, and reload them transparently in memory when this values are
|
||||
requested in some way.
|
||||
So you may ask why don't let the operating system VM do the work
|
||||
for us. There are two main reasons: in Redis even a large value
|
||||
stored at a given key, for instance a 1 million elements list, is
|
||||
not allocated in a contiguous piece of memory. It's actually
|
||||
**very** fragmented since Redis uses quite aggressive object
|
||||
sharing and allocated Redis Objects structures reuse.
|
||||
So you can imagine the memory layout composed of 4096 bytes pages
|
||||
that actually contain different parts of different large values.
|
||||
Not only, but a lot of values that are large enough for us to swap
|
||||
out to disk, like a 1024k value, is just one quarter the size of a
|
||||
memory page, and likely in the same page there are other values
|
||||
that are not rarely used. So this value wil never be swapped out by
|
||||
the operating system. This is the first reason for implementing
|
||||
application-level virtual memory in Redis.
|
||||
There is another one, as important as the first. A complex object
|
||||
in memory like a list or a set is something **10 times bigger**
|
||||
than the same object serialized on disk. Probably you already
|
||||
noticed how Redis snapshots on disk are damn smaller compared to
|
||||
the memory usage of Redis for the same objects. This happens
|
||||
because when data is in memory is full of pointers, reference
|
||||
counters and other metadata. Add to this malloc fragmentation and
|
||||
need to return word-aligned chunks of memory and you have a clear
|
||||
picture of what happens. So this means to have 10 times the I/O
|
||||
between memory and disk than otherwise needed.
|
||||
Is there something I can do to lower the Redis memory usage?
|
||||
============================================================
|
||||
|
||||
Yes, try to compile it with 32 bit target if you are using a 64 bit
|
||||
box.
|
||||
If you are using Redis >= 1.3, try using the Hash data type, it can
|
||||
save a lot of memory.
|
||||
If you are using hashes or any other type with values bigger than
|
||||
128 bytes try also this to lower the RSS usage (Resident Set Size):
|
||||
EXPORT MMAP\_THRESHOLD=4096
|
||||
I have an empty Redis server but INFO and logs are reporting megabytes of memory in use!
|
||||
========================================================================================
|
||||
|
||||
This may happen and it's prefectly ok. Redis objects are small C
|
||||
structures allocated and freed a lot of times. This costs a lot of
|
||||
CPU so instead of being freed, released objects are taken into a
|
||||
free list and reused when needed. This memory is taken exactly by
|
||||
this free objects ready to be reused.
|
||||
What happens if Redis runs out of memory?
|
||||
=========================================
|
||||
|
||||
With modern operating systems malloc() returning NULL is not
|
||||
common, usually the server will start swapping and Redis
|
||||
performances will be disastrous so you'll know it's time to use
|
||||
more Redis servers or get more RAM.
|
||||
The INFO command (work in progress in this days) will report the
|
||||
amount of memory Redis is using so you can write scripts that
|
||||
monitor your Redis servers checking for critical conditions.
|
||||
You can also use the "maxmemory" option in the config file to put a
|
||||
limit to the memory Redis can use. If this limit is reached Redis
|
||||
will start to reply with an error to write commands (but will
|
||||
continue to accept read-only commands).
|
||||
Does Redis use more memory running in 64 bit boxes? Can I use 32 bit Redis in 64 bit systems?
|
||||
=============================================================================================
|
||||
|
||||
Redis uses a lot more memory when compiled for 64 bit target,
|
||||
especially if the dataset is composed of many small keys and
|
||||
values. Such a database will, for instance, consume 50 MB of RAM
|
||||
when compiled for the 32 bit target, and 80 MB for 64 bit! That's a
|
||||
big difference.
|
||||
You can run 32 bit Redis binaries in a 64 bit Linux and Mac OS X
|
||||
system without problems. For OS X just use **make 32bit**. For
|
||||
Linux instead, make sure you have **libc6-dev-i386** installed,
|
||||
then use **make 32bit** if you are using the latest Git version.
|
||||
Instead for Redis <= 1.2.2 you have to edit the Makefile and
|
||||
replace "-arch i386" with "-m32".
|
||||
If your application is already able to perform application-level
|
||||
sharding, it is very advisable to run N instances of Redis 32bit
|
||||
against a big 64 bit Redis box (with more than 4GB of RAM) instead
|
||||
than a single 64 bit instance, as this is much more memory
|
||||
efficient.
|
||||
How much time it takes to load a big database at server startup?
|
||||
================================================================
|
||||
|
||||
Just an example on normal hardware: It takes about 45 seconds to
|
||||
restore a 2 GB database on a fairly standard system, no RAID. This
|
||||
can give you some kind of feeling about the order of magnitude of
|
||||
the time needed to load data when you restart the server.
|
||||
Background saving is failing with a fork() error under Linux even if I've a lot of free RAM!
|
||||
============================================================================================
|
||||
|
||||
Short answer: ``echo 1 > /proc/sys/vm/overcommit_memory`` :)
|
||||
And now the long one:
|
||||
Redis background saving schema relies on the copy-on-write semantic
|
||||
of fork in modern operating systems: Redis forks (creates a child
|
||||
process) that is an exact copy of the parent. The child process
|
||||
dumps the DB on disk and finally exits. In theory the child should
|
||||
use as much memory as the parent being a copy, but actually thanks
|
||||
to the copy-on-write semantic implemented by most modern operating
|
||||
systems the parent and child process will *share* the common memory
|
||||
pages. A page will be duplicated only when it changes in the child
|
||||
or in the parent. Since in theory all the pages may change while
|
||||
the child process is saving, Linux can't tell in advance how much
|
||||
memory the child will take, so if the ``overcommit_memory`` setting
|
||||
is set to zero fork will fail unless there is as much free RAM as
|
||||
required to really duplicate all the parent memory pages, with the
|
||||
result that if you have a Redis dataset of 3 GB and just 2 GB of
|
||||
free memory it will fail.
|
||||
Setting ``overcommit_memory`` to 1 says Linux to relax and perform
|
||||
the fork in a more optimistic allocation fashion, and this is
|
||||
indeed what you want for Redis.
|
||||
A good source to understand how Linux Virtual Memory work and other
|
||||
alternatives for ``overcommit_memory`` and ``overcommit_ratio`` is
|
||||
this classic from Red Hat Magaize, "Understanding Virtual Memory":
|
||||
`http://www.redhat.com/magazine/001nov04/features/vm/ <http://www.redhat.com/magazine/001nov04/features/vm/>`_
|
||||
Are Redis on disk snapshots atomic?
|
||||
===================================
|
||||
|
||||
Yes, redis background saving process is always fork(2)ed when the
|
||||
server is outside of the execution of a command, so every command
|
||||
reported to be atomic in RAM is also atomic from the point of view
|
||||
of the disk snapshot.
|
||||
Redis is single threaded, how can I exploit multiple CPU / cores?
|
||||
=================================================================
|
||||
|
||||
Simply start multiple instances of Redis in different ports in the
|
||||
same box and threat them as different servers! Given that Redis is
|
||||
a distributed database anyway in order to scale you need to think
|
||||
in terms of multiple computational units. At some point a single
|
||||
box may not be enough anyway.
|
||||
In general key-value databases are very scalable because of the
|
||||
property that different keys can stay on different servers
|
||||
independently.
|
||||
In Redis there are client libraries such Redis-rb (the Ruby client)
|
||||
that are able to handle multiple servers automatically using
|
||||
*consistent hashing*. We are going to implement consistent hashing
|
||||
in all the other major client libraries. If you use a different
|
||||
language you can implement it yourself otherwise just hash the key
|
||||
before to SET / GET it from a given server. For example imagine to
|
||||
have N Redis servers, server-0, server-1, ..., server-N. You want
|
||||
to store the key "foo", what's the right server where to put "foo"
|
||||
in order to distribute keys evenly among different servers? Just
|
||||
perform the *crc* = CRC32("foo"), then *servernum* = *crc* % N (the
|
||||
rest of the division for N). This will give a number between 0 and
|
||||
N-1 for every key. Connect to this server and store the key. The
|
||||
same for gets.
|
||||
This is a basic way of performing key partitioning, consistent
|
||||
hashing is much better and this is why after Redis 1.0 will be
|
||||
released we'll try to implement this in every widely used client
|
||||
library starting from Python and PHP (Ruby already implements this
|
||||
support).
|
||||
I'm using some form of key hashing for partitioning, but what about SORT BY?
|
||||
============================================================================
|
||||
|
||||
With `SORT <SortCommand.html>`_ BY you need that all the
|
||||
*weight keys* are in the same Redis instance of the list/set you
|
||||
are trying to sort. In order to make this possible we developed a
|
||||
concept called *key tags*. A key tag is a special pattern inside a
|
||||
key that, if preset, is the only part of the key hashed in order to
|
||||
select the server for this key. For example in order to hash the
|
||||
key "foo" I simply perform the CRC32 checksum of the whole string,
|
||||
but if this key has a pattern in the form of the characters {...} I
|
||||
only hash this substring. So for example for the key "foo{bared}"
|
||||
the key hashing code will simply perform the CRC32 of "bared". This
|
||||
way using key tags you can ensure that related keys will be stored
|
||||
on the same Redis instance just using the same key tag for all this
|
||||
keys. Redis-rb already implements key tags.
|
||||
What is the maximum number of keys a single Redis instance can hold? and what the max number of elements in a List, Set, Ordered Set?
|
||||
=====================================================================================================================================
|
||||
|
||||
In theory Redis can handle up to
|
||||
2\ :sup:`32 keys, and was tested in practice to handle at least 150 million of keys per instance. We are working in order to experiment with larger values.Every list, set, and ordered set, can hold 2`\ 32
|
||||
elements.
|
||||
Actually Redis internals are ready to allow up to
|
||||
2\ :sup:`64 elements but the current disk dump format don't support this, and there is a lot time to fix this issues in the future as currently even with 128 GB of RAM it's impossible to reach 2`\ 32
|
||||
elements.
|
||||
What Redis means actually?
|
||||
==========================
|
||||
|
||||
Redis means two things:
|
||||
|
||||
- it's a joke on the word Redistribute (instead to use just a
|
||||
Relational DB redistribute your workload among Redis servers)
|
||||
- it means REmote DIctionary Server
|
||||
|
||||
Why did you started the Redis project?
|
||||
======================================
|
||||
|
||||
In order to scale `LLOOGG <http://lloogg.com>`_. But after I got
|
||||
the basic server working I liked the idea to share the work with
|
||||
other guys, and Redis was turned into an open source project.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,134 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**Features: Contents**
|
||||
`Features (DRAFT) <#Features%20(DRAFT)>`_
|
||||
`Speed <#Speed>`_
|
||||
`Persistence <#Persistence>`_
|
||||
`Support for Data Structures <#Support%20for%20Data%20Structures>`_
|
||||
`Atomic Operations <#Atomic%20Operations>`_
|
||||
`Variety of Supported Languages <#Variety%20of%20Supported%20Languages>`_
|
||||
`Master/Slave Replication <#Master/Slave%20Replication>`_
|
||||
`Sharding <#Sharding>`_
|
||||
`Hot Backups <#Hot%20Backups>`_
|
||||
`Simple to Install, Setup and Manage <#Simple%20to%20Install,%20Setup%20and%20Manage>`_
|
||||
`Portable <#Portable>`_
|
||||
`Liberal Licensing <#Liberal%20Licensing>`_
|
||||
`What's next? <#What's%20next?>`_
|
||||
Features
|
||||
========
|
||||
|
||||
#sidebar `SideBar <SideBar.html>`_
|
||||
Features (DRAFT)
|
||||
================
|
||||
|
||||
Checking Redis for the first time? Here your will find the most
|
||||
important features, and pointers to a lot more information.
|
||||
Speed
|
||||
-----
|
||||
|
||||
Redis is written in ANSI C, and loads the whole dataset in memory,
|
||||
so it is wicked ***fast**!* Up to 110,000
|
||||
`SETs <SETs.html>`_/second, 81,000 GETs/second can be achieved in
|
||||
an entry level Linux box. Read more about Redis
|
||||
`Speed <Speed.html>`_.
|
||||
Also Redis supports `Pipelining <Pipelining.html>`_ of commands and
|
||||
`getting and setting múltiple values in a single command <MultiBulkCommands.html>`_
|
||||
to speed up communication with the client libraries.
|
||||
Persistence
|
||||
-----------
|
||||
|
||||
While all the data lives in memory, changes are *asynchronously*
|
||||
saved on disk using flexible policies based on elapsed time and/or
|
||||
number of updates since last save.
|
||||
If you can't afford losing some data, starting on version 1.1
|
||||
(currently in beta but you can download it from the Git repository)
|
||||
Redis supports an append-only file persistence mode. Check more on
|
||||
`Persistence <Persistence.html>`_, or read the
|
||||
`AppendOnlyFileHowto <AppendOnlyFileHowto.html>`_ for more
|
||||
information.
|
||||
Support for Data Structures
|
||||
---------------------------
|
||||
|
||||
Values in Redis can be `Strings <Strings.html>`_ as in a
|
||||
conventional key-value store, but also `Lists <Lists.html>`_,
|
||||
`Sets <Sets.html>`_, and `SortedSets <SortedSets.html>`_ (to be
|
||||
support in `version 1.1 <RoadMap.html>`_). This data types allow
|
||||
pushing/poping elements, or adding/removing them, also perform
|
||||
server side union, intersection, difference between sets, and so
|
||||
forth depending on the types. Redis supports different kind of
|
||||
sorting abilities for `Sets <Sets.html>`_ and
|
||||
`Lists <Lists.html>`_.
|
||||
You can think in Redis as a **Data Structures Server**, that allows
|
||||
you to model non trivial problems. Read
|
||||
`Data Types <DataTypes.html>`_ to learn more about the way Redis
|
||||
handle `Strings <Strings.html>`_, and the
|
||||
`Commands <Commands.html>`_ supported by `Lists <Lists.html>`_,
|
||||
`Sets <Sets.html>`_ and `SortedSets <SortedSets.html>`_
|
||||
Atomic Operations
|
||||
-----------------
|
||||
|
||||
Redis operations working on the different Data Types are
|
||||
**atomic**, so setting or increasing a key, adding and removing
|
||||
elements from a set, increasing a counter will all be accomplished
|
||||
safely.
|
||||
Variety of Supported Languages
|
||||
------------------------------
|
||||
|
||||
Ruby, Python, Twisted Python, PHP, Erlang, Tcl, Perl, Lua, Java,
|
||||
Scala, Clojure, choose your poison. Check the list of
|
||||
`Supported Languages <SupportedLanguages.html>`_ for all the
|
||||
details.
|
||||
If your favorite language is not supported yet, you can write your
|
||||
own client library, as the `Protocol <ProtocolSpecification.html>`_
|
||||
is pretty simple.
|
||||
Master/Slave Replication
|
||||
------------------------
|
||||
|
||||
Redis supports a very simple and fast Master/Slave replication. Is
|
||||
so simple it takes only one line in the
|
||||
`configuration file <Configuration.html>`_ to set it up, and 21
|
||||
seconds for a Slave to complete the initial sync of 10 MM key set
|
||||
in a Amazon EC2 instance.
|
||||
Read more about Master/Slave `Replication <Replication.html>`_.
|
||||
Sharding
|
||||
--------
|
||||
|
||||
Distributing the dataset across multiple Redis instances is easy in
|
||||
Redis, as in any other key-value store. And this depends basically
|
||||
on the `Languages <Supported.html>`_ client libraries being able to
|
||||
do so.
|
||||
Read more about `Sharding <Sharding.html>`_ if you want to know
|
||||
more abour distributing data and workload in Redis.
|
||||
Hot Backups
|
||||
-----------
|
||||
|
||||
TODO
|
||||
Simple to Install, Setup and Manage
|
||||
-----------------------------------
|
||||
|
||||
Installing Redis requires little more than downloading it,
|
||||
uncompressing it and running make. Management is near zero, so you
|
||||
can start using Redis in a matter of minutes.
|
||||
Go on and read about Redis `installation <Installation.html>`_, its
|
||||
`Setup <Setup.html>`_ and `Management <Management.html>`_.
|
||||
Portable
|
||||
--------
|
||||
|
||||
Redis is written in ANSI C and works in most POSIX systems like
|
||||
Linux, BSD, Mac OS X, Solaris, and so on. Redis is reported to
|
||||
compile and work under WIN32 if compiled with Cygwin, but there is
|
||||
no official support for Windows currently.
|
||||
Liberal Licensing
|
||||
-----------------
|
||||
|
||||
Redis is free software released under the very liberal BSD license.
|
||||
What's next?
|
||||
------------
|
||||
|
||||
Want to get started with Redis? Try the
|
||||
`Quick Start <QuickStart.html>`_ you will be up and running in just
|
||||
a matter of minutes.
|
||||
Check the `Code Samples <CodeSamples.html>`_ and find how you can
|
||||
use Redis with your favorite programming language.
|
||||
`Compare <Comparisons.html>`_ Redis with other key-value stores,
|
||||
like Tokyo Cabinet or Memcached.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,19 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**FlushallCommand: Contents**
|
||||
`FLUSHALL <#FLUSHALL>`_
|
||||
`Return value <#Return%20value>`_
|
||||
FlushallCommand
|
||||
===============
|
||||
|
||||
#sidebar `GenericCommandsSidebar <GenericCommandsSidebar.html>`_
|
||||
FLUSHALL
|
||||
========
|
||||
|
||||
Delete all the keys of all the existing databases, not just the
|
||||
currently selected one. This command never fails.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Status code reply <ReplyTypes.html>`_
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,19 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**FlushdbCommand: Contents**
|
||||
`FLUSHDB <#FLUSHDB>`_
|
||||
`Return value <#Return%20value>`_
|
||||
FlushdbCommand
|
||||
==============
|
||||
|
||||
#sidebar `GenericCommandsSidebar <GenericCommandsSidebar.html>`_
|
||||
FLUSHDB
|
||||
=======
|
||||
|
||||
Delete all the keys of the currently selected DB. This command
|
||||
never fails.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Status code reply <ReplyTypes.html>`_
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,63 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**FromSqlToDataStructures: Contents**
|
||||
`Introduction (IDEA MORE THAN A DRAFT) <#Introduction%20(IDEA%20MORE%20THAN%20A%20DRAFT)>`_
|
||||
`Data Structures <#Data%20Structures>`_
|
||||
`Dude where is my SELECT statement? <#Dude%20where%20is%20my%20SELECT%20statement?>`_
|
||||
`LISTs <#LISTs>`_
|
||||
`SETs <#SETs>`_
|
||||
`SORT to the rescue <#SORT%20to%20the%20rescue>`_
|
||||
`SORT BY <#SORT%20BY>`_
|
||||
`HASHEs <#HASHEs>`_
|
||||
FromSqlToDataStructures
|
||||
=======================
|
||||
|
||||
Introduction (IDEA MORE THAN A DRAFT)
|
||||
=====================================
|
||||
|
||||
**¿Coming from SQLand?** *¿Who doesn't?* Redis is simple,
|
||||
*primitive* when comapred to the world you are used to in the world
|
||||
of Relational Database Managers (RDBMS) and Structure Query
|
||||
Language (SQL), here you will find insight to build bridges between
|
||||
both worlds to model real life problems.
|
||||
Data Structures
|
||||
---------------
|
||||
|
||||
When I was young, happy and single ;) I studied **Data Structures**
|
||||
at the university, actually I learnt Data Structures and Algorithms
|
||||
*before* learning anything about Databases, and particularly RDBMS
|
||||
and SQL. This is natural because you need to know about Data
|
||||
Structures and Algorithms to understand a Database.
|
||||
Redis can be seen as a **Data Structures Server**, a very simple
|
||||
interface to a extremly fast and efficient
|
||||
Dude where is my SELECT statement?
|
||||
----------------------------------
|
||||
|
||||
LISTs
|
||||
-----
|
||||
|
||||
In SQL there is no such thing as a "natural" order, a SELECT
|
||||
statement without a ORDER BY clause will return data in a undefined
|
||||
order. In Redis `LISTs <LISTs.html>`_ address the problem of
|
||||
natural ordering, ...
|
||||
SETs
|
||||
----
|
||||
|
||||
So you have a bunch of unordered data,
|
||||
SORT to the rescue
|
||||
------------------
|
||||
|
||||
But sometimes we *need* to actually sort a LIST in a order
|
||||
different from its natural or take a SET and have it ordered, there
|
||||
is where the *fast* SORT commands comes handy...
|
||||
SORT BY
|
||||
~~~~~~~
|
||||
|
||||
Just SORTing keys would be kind of boring, sometimes useless right?
|
||||
Well, you can SORT...
|
||||
HASHEs
|
||||
------
|
||||
|
||||
Umm, sorry you will have to wait for a
|
||||
`upcoming version of Redis <RoadMap.html>`_ to have Hashes, but
|
||||
here are Idioms you should house to manage Dictionary like data...
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,25 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**GenericCommandsSidebar: Contents**
|
||||
GenericCommandsSidebar
|
||||
======================
|
||||
|
||||
== Generic Commands ==
|
||||
|
||||
- `EXISTS <ExistsCommand.html>`_
|
||||
- `DEL <DelCommand.html>`_
|
||||
- `TYPE <TypeCommand.html>`_
|
||||
- `KEYS <KeysCommand.html>`_
|
||||
- `RANDOMKEY <RandomkeyCommand.html>`_
|
||||
- `RENAME <RenameCommand.html>`_
|
||||
- `RENAMENX <RenamenxCommand.html>`_
|
||||
- `DBSIZE <DbsizeCommand.html>`_
|
||||
- `EXPIRE <ExpireCommand.html>`_
|
||||
- `PERSIST <ExpireCommand.html>`_
|
||||
- `TTL <TtlCommand.html>`_
|
||||
- `SELECT <SelectCommand.html>`_
|
||||
- `MOVE <MoveCommand.html>`_
|
||||
- `FLUSHDB <FlushdbCommand.html>`_
|
||||
- `FLUSHALL <FlushallCommand.html>`_
|
||||
- `Redis Transactions <MultiExecCommand.html>`_
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,22 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**GetCommand: Contents**
|
||||
`GET \_key\_ <#GET%20_key_>`_
|
||||
`Return value <#Return%20value>`_
|
||||
GetCommand
|
||||
==========
|
||||
|
||||
#sidebar `StringCommandsSidebar <StringCommandsSidebar.html>`_
|
||||
GET \_key\_
|
||||
===========
|
||||
|
||||
*Time complexity: O(1)*
|
||||
Get the value of the specified key. If the keydoes not exist the
|
||||
special value 'nil' is returned.If the value stored at *key* is not
|
||||
a string an erroris returned because GET can only handle string
|
||||
values.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Bulk reply <ReplyTypes.html>`_
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,24 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**GetbitCommand: Contents**
|
||||
`GETBIT \_key\_ \_offset\_ (Redis > <#GETBIT%20_key_%20_offset_%20(Redis%20%3E>`_
|
||||
`Return value <#Return%20value>`_
|
||||
GetbitCommand
|
||||
=============
|
||||
|
||||
GETBIT \_key\_ \_offset\_ (Redis >
|
||||
==================================
|
||||
|
||||
2.1.8) = *Time complexity: O(1)*
|
||||
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.
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Integer reply <ReplyTypes.html>`_, specifically: the bit value
|
||||
stored at *offset*.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,32 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**GetsetCommand: Contents**
|
||||
`GETSET \_key\_ \_value\_ <#GETSET%20_key_%20_value_>`_
|
||||
`Return value <#Return%20value>`_
|
||||
`Design patterns <#Design%20patterns>`_
|
||||
GetsetCommand
|
||||
=============
|
||||
|
||||
#sidebar `StringCommandsSidebar <StringCommandsSidebar.html>`_
|
||||
GETSET \_key\_ \_value\_
|
||||
========================
|
||||
|
||||
*Time complexity: O(1)*
|
||||
GETSET is an atomic *set this value and return the old value*
|
||||
command.Set *key* to the string *value* and return the old value
|
||||
stored at *key*.The string can't be longer than 1073741824 bytes (1
|
||||
GB).
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Bulk reply <ReplyTypes.html>`_
|
||||
Design patterns
|
||||
---------------
|
||||
|
||||
GETSET can be used together with INCR for counting with atomic
|
||||
reset whena given condition arises. For example a process may call
|
||||
INCR against thekey *mycounter* every time some event occurred, but
|
||||
from time totime we need to get the value of the counter and reset
|
||||
it to zero atomicallyusing ``GETSET mycounter 0``.
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,111 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**HackingStrings: Contents**
|
||||
`Hacking Strings <#Hacking%20Strings>`_
|
||||
`Creating Redis Strings <#Creating%20Redis%20Strings>`_
|
||||
HackingStrings
|
||||
==============
|
||||
|
||||
Hacking Strings
|
||||
===============
|
||||
|
||||
The implementation of Redis strings is contained in ****sds.c**** (
|
||||
sds stands for Simple Dynamic Strings ).
|
||||
The C structure *sdshdr* declared in **sds.h** represents a Redis
|
||||
string:
|
||||
::
|
||||
|
||||
struct sdshdr {
|
||||
long len;
|
||||
long free;
|
||||
char buf[];
|
||||
};
|
||||
|
||||
The *buf* character array stores the actual string.
|
||||
The *len* field stores the length of *buf*. This makes obtaining
|
||||
the length of a Redis string an O(1) operation.
|
||||
The *free* field stores the number of additional bytes available
|
||||
for use.
|
||||
Together the *len* and *free* field can be thought of as holding
|
||||
the metadata of the *buf* character array.
|
||||
Creating Redis Strings
|
||||
----------------------
|
||||
|
||||
A new data type named ``sds`` is defined in **sds.h** to be a
|
||||
synonymn for a character pointer:
|
||||
::
|
||||
|
||||
typedef char *sds;
|
||||
|
||||
``sdsnewlen`` function defined in **sds.c** creates a new Redis
|
||||
String:
|
||||
::
|
||||
|
||||
sds sdsnewlen(const void *init, size_t initlen) {
|
||||
struct sdshdr *sh;
|
||||
|
||||
sh = zmalloc(sizeof(struct sdshdr)+initlen+1);
|
||||
#ifdef SDS_ABORT_ON_OOM
|
||||
if (sh == NULL) sdsOomAbort();
|
||||
#else
|
||||
if (sh == NULL) return NULL;
|
||||
#endif
|
||||
sh->len = initlen;
|
||||
sh->free = 0;
|
||||
if (initlen) {
|
||||
if (init) memcpy(sh->buf, init, initlen);
|
||||
else memset(sh->buf,0,initlen);
|
||||
}
|
||||
sh->buf[initlen] = '\0';
|
||||
return (char*)sh->buf;
|
||||
}
|
||||
|
||||
Remember a Redis string is a variable of type ``struct sdshdr``.
|
||||
But ``sdsnewlen`` returns a character pointer!!
|
||||
That's a trick and needs some explanation.
|
||||
Suppose I create a Redis string using ``sdsnewlen`` like below:
|
||||
::
|
||||
|
||||
sdsnewlen("redis", 5);
|
||||
|
||||
This creates a new variable of type ``struct sdshdr`` allocating
|
||||
memory for *len* and *free* fields as well as for the *buf*
|
||||
character array.
|
||||
::
|
||||
|
||||
sh = zmalloc(sizeof(struct sdshdr)+initlen+1); // initlen is length of init argument.
|
||||
|
||||
After ``sdsnewlen`` succesfully creates a Redis string the result
|
||||
is something like:
|
||||
::
|
||||
|
||||
-----------
|
||||
|5|0|redis|
|
||||
-----------
|
||||
^ ^
|
||||
sh sh->buf
|
||||
|
||||
``sdsnewlen`` returns sh->buf to the caller.
|
||||
What do you do if you need to free the Redis string pointed by
|
||||
``sh``?
|
||||
You want the pointer ``sh`` but you only have the pointer
|
||||
``sh->buf``.
|
||||
Can you get the pointer ``sh`` from ``sh->buf``?
|
||||
Yes. Pointer arithmetic. Notice from the above ASCII art that if
|
||||
you subtract the size of two longs from ``sh->buf`` you get the
|
||||
pointer ``sh``.
|
||||
The sizeof two longs happens to be the size of ``struct sdshdr``.
|
||||
Look at ``sdslen`` function and see this trick at work:
|
||||
::
|
||||
|
||||
size_t sdslen(const sds s) {
|
||||
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
|
||||
return sh->len;
|
||||
}
|
||||
|
||||
Knowing this trick you could easily go through the rest of the
|
||||
functions in **sds.c**.
|
||||
The Redis string implementation is hidden behind an interface that
|
||||
accepts only character pointers. The users of Redis strings need
|
||||
not care about how its implemented and treat Redis strings as a
|
||||
character pointer.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,21 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**HashCommandsSidebar: Contents**
|
||||
HashCommandsSidebar
|
||||
===================
|
||||
|
||||
== Hash Commands ==
|
||||
|
||||
- `HSET <HsetCommand.html>`_
|
||||
- `HGET <HgetCommand.html>`_
|
||||
- `HSETNX <HsetnxCommand.html>`_
|
||||
- `HMSET <HmsetCommand.html>`_
|
||||
- `HMGET <HmgetCommand.html>`_
|
||||
- `HINCRBY <HincrbyCommand.html>`_
|
||||
- `HEXISTS <HexistsCommand.html>`_
|
||||
- `HDEL <HdelCommand.html>`_
|
||||
- `HLEN <HlenCommand.html>`_
|
||||
- `HKEYS <HgetallCommand.html>`_
|
||||
- `HVALS <HgetallCommand.html>`_
|
||||
- `HGETALL <HgetallCommand.html>`_
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,61 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**Hashes: Contents**
|
||||
`Redis Hash Type <#Redis%20Hash%20Type>`_
|
||||
`Implementation details <#Implementation%20details>`_
|
||||
Hashes
|
||||
======
|
||||
|
||||
#sidebar `HashCommandsSidebar <HashCommandsSidebar.html>`_
|
||||
Redis Hash Type
|
||||
===============
|
||||
|
||||
Redis Hashes are unordered maps of `Redis Strings <String.html>`_
|
||||
between fields and values. It is possible to add, remove, test for
|
||||
existence of fields in O(1) amortized time. It is also possible to
|
||||
enumerate all the keys, values, or both, in O(N) (where N is the
|
||||
number of fields inside the hash).
|
||||
Redis Hashes are interesting because they are very well suited to
|
||||
represent objects. For instance web applications users can be
|
||||
represented by a Redis Hash containing fields such username,
|
||||
encrpypted\_password, lastlogin, and so forth.
|
||||
Another very important property of Redis Hashes is that they use
|
||||
very little memory for hashes composed of a small number of fields
|
||||
(configurable, check redis.conf for details), compared to storing
|
||||
every field as a top level Redis key. This is obtained using a
|
||||
different specialized representation for small hashes. See the
|
||||
implementation details paragraph below for more information.
|
||||
Commands operating on hashes try to make a good use of the return
|
||||
value in order to signal the application about previous existence
|
||||
of fields. For instance the `HSET <HsetCommand.html>`_ command will
|
||||
return 1 if the field set was not already present in the hash,
|
||||
otherwise will return 0 (and the user knows this was just an update
|
||||
operation).
|
||||
The max number of fields in a set is 232-1 (4294967295, more than 4
|
||||
billion of members per hash).
|
||||
Implementation details
|
||||
======================
|
||||
|
||||
The obvious internal representation of hashes is indeed an hash
|
||||
table, as the name of the data structure itself suggests. Still the
|
||||
drawback of this representation is that there is a lot of space
|
||||
overhead for hash table metadata.
|
||||
Because one of the most interesting uses of Hashes is object
|
||||
encoding, and objects are often composed of a few fields each,
|
||||
Redis uses a different internal representation for small hashes
|
||||
(for Redis to consider a hash small, this must be composed a
|
||||
limited number of fields, and each field and value can't exceed a
|
||||
given number of bytes. All this is user-configurable).
|
||||
Small hashes are thus encoded using a data structure called zipmap
|
||||
(is not something you can find in a CS book, the name is a Redis
|
||||
invention), that is a very memory efficient data structure to
|
||||
represent string to string maps, at the cost of being O(N) instead
|
||||
of O(1) for most operations. Since the constant times of this data
|
||||
structure are very small, and the zipmaps are converted into real
|
||||
hash tables once they are big enough, the amortized time of Redis
|
||||
hashes is still O(1), and in the practice small zipmaps are not
|
||||
slower than small hash tables because they are designed for good
|
||||
cache locality and fast access.
|
||||
The result is that small hashes are both memory efficient and fast,
|
||||
while bigger hashes are fast but not as memory efficient than small
|
||||
hashes.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,22 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**HdelCommand: Contents**
|
||||
`HDEL \_key\_ \_field\_ (Redis > <#HDEL%20_key_%20_field_%20(Redis%20%3E>`_
|
||||
`Return value <#Return%20value>`_
|
||||
HdelCommand
|
||||
===========
|
||||
|
||||
#sidebar `HashCommandsSidebar <HashCommandsSidebar.html>`_
|
||||
HDEL \_key\_ \_field\_ (Redis >
|
||||
===============================
|
||||
|
||||
1.3.10)= *Time complexity: O(1)*
|
||||
Remove the specified *field* from an hash stored at *key*.
|
||||
|
||||
If the *field* was present in the hash it is deleted and 1 is
|
||||
returned, otherwise 0 is returned and no operation is performed.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Integer reply <ReplyTypes.html>`_
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,22 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**HexistsCommand: Contents**
|
||||
`HEXISTS \_key\_ \_field\_ (Redis > <#HEXISTS%20_key_%20_field_%20(Redis%20%3E>`_
|
||||
`Return value <#Return%20value>`_
|
||||
HexistsCommand
|
||||
==============
|
||||
|
||||
#sidebar `HashCommandsSidebar <HashCommandsSidebar.html>`_
|
||||
HEXISTS \_key\_ \_field\_ (Redis >
|
||||
==================================
|
||||
|
||||
1.3.10)= *Time complexity: O(1)*
|
||||
Return 1 if the hash stored at *key* contains the specified
|
||||
*field*.
|
||||
|
||||
Return 0 if the *key* is not found or the *field* is not present.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Integer reply <ReplyTypes.html>`_
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,23 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**HgetCommand: Contents**
|
||||
`HGET \_key\_ \_field\_ (Redis > <#HGET%20_key_%20_field_%20(Redis%20%3E>`_
|
||||
`Return value <#Return%20value>`_
|
||||
HgetCommand
|
||||
===========
|
||||
|
||||
#sidebar `HashCommandsSidebar <HashCommandsSidebar.html>`_
|
||||
HGET \_key\_ \_field\_ (Redis >
|
||||
===============================
|
||||
|
||||
1.3.10)= *Time complexity: O(1)*
|
||||
If *key* holds a hash, retrieve the value associated to the
|
||||
specified *field*.
|
||||
|
||||
If the *field* is not found or the *key* does not exist, a special
|
||||
'nil' value is returned.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Bulk reply <ReplyTypes.html>`_
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,33 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**HgetallCommand: Contents**
|
||||
`HKEYS \_key\_ (Redis > <#HKEYS%20_key_%20(Redis%20%3E>`_
|
||||
`HVALS \_key\_ (Redis > <#HVALS%20_key_%20(Redis%20%3E>`_
|
||||
`HGETALL \_key\_ (Redis > <#HGETALL%20_key_%20(Redis%20%3E>`_
|
||||
`Return value <#Return%20value>`_
|
||||
HgetallCommand
|
||||
==============
|
||||
|
||||
#sidebar `HashCommandsSidebar <HashCommandsSidebar.html>`_
|
||||
HKEYS \_key\_ (Redis >
|
||||
======================
|
||||
|
||||
1.3.10)=
|
||||
HVALS \_key\_ (Redis >
|
||||
======================
|
||||
|
||||
1.3.10)=
|
||||
HGETALL \_key\_ (Redis >
|
||||
========================
|
||||
|
||||
1.3.10)=
|
||||
*Time complexity: O(N), where N is the total number of fields in the hash*
|
||||
HKEYS returns all the fields names contained into a hash, HVALS all
|
||||
the associated values, while HGETALL returns both the fields and
|
||||
values in the form of *field1*, *value1*, *field2*, *value2*, ...,
|
||||
*fieldN*, *valueN*.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Multi Bulk Reply <ReplyTypes.html>`_
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,37 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**HincrbyCommand: Contents**
|
||||
`HINCRBY \_key\_ \_field\_ \_value\_ (Redis > <#HINCRBY%20_key_%20_field_%20_value_%20(Redis%20%3E>`_
|
||||
`Examples <#Examples>`_
|
||||
`Return value <#Return%20value>`_
|
||||
HincrbyCommand
|
||||
==============
|
||||
|
||||
HINCRBY \_key\_ \_field\_ \_value\_ (Redis >
|
||||
============================================
|
||||
|
||||
1.3.10)= *Time complexity: O(1)*
|
||||
Increment the number stored at *field* in the hash at *key* by
|
||||
*value*. If *key* does not exist, a new key holding a hash is
|
||||
created. If *field* does not exist or holds a string, the value is
|
||||
set to 0 before applying the operation.
|
||||
|
||||
The range of values supported by HINCRBY is limited to 64 bit
|
||||
signed integers.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
Since the *value* argument is signed you can use this command to
|
||||
perform both increments and decrements:
|
||||
::
|
||||
|
||||
HINCRBY key field 1 (increment by one)
|
||||
HINCRBY key field -1 (decrement by one, just like the DECR command)
|
||||
HINCRBY key field -10 (decrement by 10)
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Integer reply <ReplyTypes.html>`_ The new value at *field* after
|
||||
the increment operation.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,21 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**HlenCommand: Contents**
|
||||
`HLEN \_key\_ (Redis > <#HLEN%20_key_%20(Redis%20%3E>`_
|
||||
`Return value <#Return%20value>`_
|
||||
HlenCommand
|
||||
===========
|
||||
|
||||
#sidebar `HashCommandsSidebar <HashCommandsSidebar.html>`_
|
||||
HLEN \_key\_ (Redis >
|
||||
=====================
|
||||
|
||||
1.3.10)= *Time complexity: O(1)*
|
||||
Return the number of entries (fields) contained in the hash stored
|
||||
at *key*. If the specified *key* does not exist, 0 is returned
|
||||
assuming an empty hash.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Integer reply <ReplyTypes.html>`_
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,25 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**HmgetCommand: Contents**
|
||||
`HMGET \_key\_ \_field1\_ ... \_fieldN\_ (Redis > <#HMGET%20_key_%20_field1_%20...%20_fieldN_%20(Redis%20%3E>`_
|
||||
`Return value <#Return%20value>`_
|
||||
HmgetCommand
|
||||
============
|
||||
|
||||
#sidebar `HashCommandsSidebar <HashCommandsSidebar.html>`_
|
||||
HMGET \_key\_ \_field1\_ ... \_fieldN\_ (Redis >
|
||||
================================================
|
||||
|
||||
1.3.10) =
|
||||
*Time complexity: O(N) (with N being the number of fields)*
|
||||
Retrieve the values associated to the specified *fields*.
|
||||
|
||||
If some of the specified *fields* do not exist, nil values are
|
||||
returned.Non existing keys are considered like empty hashes.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Multi Bulk Reply <ReplyTypes.html>`_ specifically a list of all
|
||||
the values associated with the specified fields, in the same order
|
||||
of the request.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,23 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**HmsetCommand: Contents**
|
||||
`HMSET \_key\_ \_field1\_ \_value1\_ ... \_fieldN\_ \_valueN\_ (Redis > <#HMSET%20_key_%20_field1_%20_value1_%20...%20_fieldN_%20_valueN_%20(Redis%20%3E>`_
|
||||
`Return value <#Return%20value>`_
|
||||
HmsetCommand
|
||||
============
|
||||
|
||||
HMSET \_key\_ \_field1\_ \_value1\_ ... \_fieldN\_ \_valueN\_ (Redis >
|
||||
======================================================================
|
||||
|
||||
1.3.10) =
|
||||
*Time complexity: O(N) (with N being the number of fields)*
|
||||
Set the respective fields to the respective values. HMSET replaces
|
||||
old values with new values.
|
||||
|
||||
If *key* does not exist, a new key holding a hash is created.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Status code reply <ReplyTypes.html>`_ Always +OK because HMSET
|
||||
can't fail
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,25 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**HsetCommand: Contents**
|
||||
`HSET \_key\_ \_field\_ \_value\_ (Redis > <#HSET%20_key_%20_field_%20_value_%20(Redis%20%3E>`_
|
||||
`Return value <#Return%20value>`_
|
||||
HsetCommand
|
||||
===========
|
||||
|
||||
#sidebar `HashCommandsSidebar <HashCommandsSidebar.html>`_
|
||||
HSET \_key\_ \_field\_ \_value\_ (Redis >
|
||||
=========================================
|
||||
|
||||
1.3.10)= *Time complexity: O(1)*
|
||||
Set the specified hash *field* to the specified *value*.
|
||||
|
||||
If *key* does not exist, a new key holding a hash is created.
|
||||
|
||||
If the field already exists, and the HSET just produced an update
|
||||
of thevalue, 0 is returned, otherwise if a new field is created 1
|
||||
is returned.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Integer reply <ReplyTypes.html>`_
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,25 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**HsetnxCommand: Contents**
|
||||
`HSETNX \_key\_ \_field\_ \_value\_ (Redis > <#HSETNX%20_key_%20_field_%20_value_%20(Redis%20%3E>`_
|
||||
`Return value <#Return%20value>`_
|
||||
HsetnxCommand
|
||||
=============
|
||||
|
||||
HSETNX \_key\_ \_field\_ \_value\_ (Redis >
|
||||
===========================================
|
||||
|
||||
1.3.10)= *Time complexity: O(1)*
|
||||
Set the specified hash *field* to the specified *value*, if *field*
|
||||
does not exist yet.
|
||||
|
||||
If *key* does not exist, a new key holding a hash is created.
|
||||
|
||||
If the field already exists, this operation has no effect and
|
||||
returns 0.Otherwise, the field is set to *value* and the operation
|
||||
returns 1.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Integer reply <ReplyTypes.html>`_
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,44 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**IncrCommand: Contents**
|
||||
`INCR \_key\_ <#INCR%20_key_>`_
|
||||
`INCRBY \_key\_ \_integer\_ <#INCRBY%20_key_%20_integer_>`_
|
||||
`DECR \_key\_ \_integer\_ <#DECR%20_key_%20_integer_>`_
|
||||
`DECRBY \_key\_ \_integer\_ <#DECRBY%20_key_%20_integer_>`_
|
||||
`Return value <#Return%20value>`_
|
||||
IncrCommand
|
||||
===========
|
||||
|
||||
#sidebar `StringCommandsSidebar <StringCommandsSidebar.html>`_
|
||||
INCR \_key\_
|
||||
============
|
||||
|
||||
INCRBY \_key\_ \_integer\_
|
||||
==========================
|
||||
|
||||
DECR \_key\_ \_integer\_
|
||||
========================
|
||||
|
||||
DECRBY \_key\_ \_integer\_
|
||||
==========================
|
||||
|
||||
*Time complexity: O(1)*
|
||||
Increment or decrement the number stored at *key* by one. If the
|
||||
key doesnot exist or contains a value of a wrong type, set the key
|
||||
to thevalue of "0" before to perform the increment or decrement
|
||||
operation.
|
||||
|
||||
INCRBY and DECRBY work just like INCR and DECR but instead
|
||||
toincrement/decrement by 1 the increment/decrement is *integer*.
|
||||
|
||||
INCR commands are limited to 64 bit signed integers.
|
||||
|
||||
Note: this is actually a string operation, that is, in Redis there
|
||||
are not "integer" types. Simply the string stored at the key is
|
||||
parsed as a base 10 64 bit signed integer, incremented, and then
|
||||
converted back as a string.
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Integer reply <ReplyTypes.html>`_, this commands will reply with
|
||||
the new value of *key* after the increment or decrement.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,49 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**InfoCommand: Contents**
|
||||
`INFO <#INFO>`_
|
||||
`Return value <#Return%20value>`_
|
||||
`Notes <#Notes>`_
|
||||
InfoCommand
|
||||
===========
|
||||
|
||||
#sidebar `ControlCommandsSidebar <ControlCommandsSidebar.html>`_
|
||||
INFO
|
||||
====
|
||||
|
||||
The info command returns different information and statistics about
|
||||
the server in an format that's simple to parse by computers and
|
||||
easy to red by huamns.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Bulk reply <ReplyTypes.html>`_, specifically in the following
|
||||
format:
|
||||
::
|
||||
|
||||
edis_version:0.07
|
||||
connected_clients:1
|
||||
connected_slaves:0
|
||||
used_memory:3187
|
||||
changes_since_last_save:0
|
||||
last_save_time:1237655729
|
||||
total_connections_received:1
|
||||
total_commands_processed:1
|
||||
uptime_in_seconds:25
|
||||
uptime_in_days:0
|
||||
|
||||
All the fields are in the form ``field:value``
|
||||
Notes
|
||||
-----
|
||||
|
||||
|
||||
- ``used_memory`` is returned in bytes, and is the total number of
|
||||
bytes allocated by the program using ``malloc``.
|
||||
- ``uptime_in_days`` is redundant since the uptime in seconds
|
||||
contains already the full uptime information, this field is only
|
||||
mainly present for humans.
|
||||
- ``changes_since_last_save`` does not refer to the number of key
|
||||
changes, but to the number of operations that produced some kind of
|
||||
change in the dataset.
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,493 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**IntroductionToRedisDataTypes: Contents**
|
||||
`A fifteen minutes introduction to Redis data types <#A%20fifteen%20minutes%20introduction%20to%20Redis%20data%20types>`_
|
||||
`Redis keys <#Redis%20keys>`_
|
||||
`The string type <#The%20string%20type>`_
|
||||
`The List type <#The%20List%20type>`_
|
||||
`First steps with Redis lists <#First%20steps%20with%20Redis%20lists>`_
|
||||
`Pushing IDs instead of the actual data in Redis lists <#Pushing%20IDs%20instead%20of%20the%20actual%20data%20in%20Redis%20lists>`_
|
||||
`Redis Sets <#Redis%20Sets>`_
|
||||
`A digression. How to get unique identifiers for strings <#A%20digression.%20How%20to%20get%20unique%20identifiers%20for%20strings>`_
|
||||
`Sorted sets <#Sorted%20sets>`_
|
||||
`Operating on ranges <#Operating%20on%20ranges>`_
|
||||
`Back to the reddit example <#Back%20to%20the%20reddit%20example>`_
|
||||
`Updating the scores of a sorted set <#Updating%20the%20scores%20of%20a%20sorted%20set>`_
|
||||
IntroductionToRedisDataTypes
|
||||
============================
|
||||
|
||||
#sidebar `RedisGuides <RedisGuides.html>`_
|
||||
A fifteen minutes introduction to Redis data types
|
||||
==================================================
|
||||
|
||||
As you already probably know Redis is not a plain key-value store,
|
||||
actually it is a **data structures server**, supporting different
|
||||
kind of values. That is, you can't just set strings as values of
|
||||
keys. All the following data types are supported as values:
|
||||
|
||||
- Binary-safe strings.
|
||||
- Lists of binary-safe strings.
|
||||
- Sets of binary-safe strings, that are collection of unique
|
||||
unsorted elements. You can think at this as a Ruby hash where all
|
||||
the keys are set to the 'true' value.
|
||||
- Sorted sets, similar to Sets but where every element is
|
||||
associated to a floating number score. The elements are taken
|
||||
sorted by score. You can think at this as Ruby hashes where the key
|
||||
is the element and the value is the score, but where elements are
|
||||
always taken in order without requiring a sorting operation.
|
||||
|
||||
It's not always trivial to grasp how this data types work and what
|
||||
to use in order to solve a given problem from the
|
||||
`Redis command reference <CommandReference.html>`_, so this
|
||||
document is a crash course to Redis data types and their most used
|
||||
patterns.
|
||||
For all the examples we'll use the **redis-cli** utility, that's a
|
||||
simple but handy command line utility to issue commands against the
|
||||
Redis server.
|
||||
Redis keys
|
||||
----------
|
||||
|
||||
Before to start talking about the different kind of values
|
||||
supported by Redis it is better to start saying that keys are not
|
||||
binary safe strings in Redis, but just strings not containing a
|
||||
space or a newline character. For instance "foo" or "123456789" or
|
||||
"foo\_bar" are valid keys, while "hello world" or "hello\\n" are
|
||||
not.
|
||||
Actually there is nothing inside the Redis internals preventing the
|
||||
use of binary keys, it's just a matter of protocol, and actually
|
||||
the new protocol introduced with Redis 1.2 (1.2 betas are 1.1.x) in
|
||||
order to implement commands like MSET, is totally binary safe.
|
||||
Still for now consider this as an hard limit as the database is
|
||||
only tested with "normal" keys.
|
||||
A few other rules about keys:
|
||||
|
||||
- Too long keys are not a good idea, for instance a key of 1024
|
||||
bytes is not a good idea not only memory-wise, but also because the
|
||||
lookup of the key in the dataset may require several costly
|
||||
key-comparisons.
|
||||
- Too short keys are not a good idea. There is no point in writing
|
||||
"u:1000:pwd" as key if you can write instead "user:1000:password",
|
||||
the latter is more readable and the added space is very little
|
||||
compared to the space used by the key object itself.
|
||||
- Try to stick with a schema. For instance "object-type:id:field"
|
||||
can be a nice idea, like in "user:1000:password". I like to use
|
||||
dots for multi-words fields, like in "comment:1234:reply.to".
|
||||
|
||||
The string type
|
||||
---------------
|
||||
|
||||
This is the simplest Redis type. If you use only this type, Redis
|
||||
will be something like a memcached server with persistence.
|
||||
Let's play a bit with the string type:
|
||||
::
|
||||
|
||||
$ ./redis-cli set mykey "my binary safe value"
|
||||
OK
|
||||
$ ./redis-cli get mykey
|
||||
my binary safe value
|
||||
|
||||
As you can see using the `Set command <SetCommand.html>`_ and the
|
||||
`Get command <GetCommand.html>`_ is trivial to set values to
|
||||
strings and have this strings returned back.
|
||||
Values can be strings (including binary data) of every kind, for
|
||||
instance you can store a jpeg image inside a key. A value can't be
|
||||
bigger than 1 Gigabyte.
|
||||
Even if strings are the basic values of Redis, there are
|
||||
interesting operations you can perform against them. For instance
|
||||
one is atomic increment:
|
||||
::
|
||||
|
||||
$ ./redis-cli set counter 100
|
||||
OK
|
||||
$ ./redis-cli incr counter
|
||||
(integer) 101
|
||||
$ ./redis-cli incr counter
|
||||
(integer) 102
|
||||
$ ./redis-cli incrby counter 10
|
||||
(integer) 112
|
||||
|
||||
The `INCR <IncrCommand.html>`_ command parses the string value as
|
||||
an integer, increments it by one, and finally sets the obtained
|
||||
value as the new string value. There are other similar commands
|
||||
like `INCRBY <IncrCommand.html>`_, `DECR <IncrCommand.html>`_ and
|
||||
`DECRBY <IncrCommand.html>`_. Actually internally it's always the
|
||||
same command, acting in a slightly different way.
|
||||
What means that INCR is atomic? That even multiple clients issuing
|
||||
INCR against the same key will never incur into a race condition.
|
||||
For instance it can't never happen that client 1 read "10", client
|
||||
2 read "10" at the same time, both increment to 11, and set the new
|
||||
value of 11. The final value will always be of 12 ad the
|
||||
read-increment-set operation is performed while all the other
|
||||
clients are not executing a command at the same time.
|
||||
Another interesting operation on string is the
|
||||
`GETSET <GetsetCommand.html>`_ command, that does just what its
|
||||
name suggests: Set a key to a new value, returning the old value,
|
||||
as result. Why this is useful? Example: you have a system that
|
||||
increments a Redis key using the `INCR <IncrCommand.html>`_ command
|
||||
every time your web site receives a new visit. You want to collect
|
||||
this information one time every hour, without loosing a single key.
|
||||
You can GETSET the key assigning it the new value of "0" and
|
||||
reading the old value back.
|
||||
The List type
|
||||
-------------
|
||||
|
||||
To explain the List data type it's better to start with a little of
|
||||
theory, as the term **List** is often used in an improper way by
|
||||
information technology folks. For instance "Python Lists" are not
|
||||
what the name may suggest (Linked Lists), but them are actually
|
||||
Arrays (the same data type is called Array in Ruby actually).
|
||||
From a very general point of view a List is just a sequence of
|
||||
ordered elements: 10,20,1,2,3 is a list, but when a list of items
|
||||
is implemented using an Array and when instead a **Linked List** is
|
||||
used for the implementation, the properties change a lot.
|
||||
Redis lists are implemented via Linked Lists, this means that even
|
||||
if you have million of elements inside a list, the operation of
|
||||
adding a new element in the head or in the tail of the list is
|
||||
performed **in constant time**. Adding a new element with the
|
||||
`LPUSH <LpushCommand.html>`_ command to the head of a ten elements
|
||||
list is the same speed as adding an element to the head of a 10
|
||||
million elements list.
|
||||
What's the downside? That accessing an element **by index** is very
|
||||
fast in lists implemented with an Array and not so fast in lists
|
||||
implemented by linked lists.
|
||||
Redis Lists are implemented with linked lists because for a
|
||||
database system is crucial to be able to add elements to a very
|
||||
long list in a very fast way. Another strong advantage is, as
|
||||
you'll see in a moment, that Redis Lists can be taken at constant
|
||||
length in constant time.
|
||||
First steps with Redis lists
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The `LPUSH <RpushCommand.html>`_ command add a new element into a
|
||||
list, on the left (on head), while the `RPUSH <RpushCommand.html>`_
|
||||
command add a new element into alist, ot the right (on tail).
|
||||
Finally the `LRANGE <LrangeCommand.html>`_ command extract ranges
|
||||
of elements from lists:
|
||||
::
|
||||
|
||||
$ ./redis-cli rpush messages "Hello how are you?"
|
||||
OK
|
||||
$ ./redis-cli rpush messages "Fine thanks. I'm having fun with Redis"
|
||||
OK
|
||||
$ ./redis-cli rpush messages "I should look into this NOSQL thing ASAP"
|
||||
OK
|
||||
$ ./redis-cli lrange messages 0 2
|
||||
1. Hello how are you?
|
||||
2. Fine thanks. I'm having fun with Redis
|
||||
3. I should look into this NOSQL thing ASAP
|
||||
|
||||
Note that `LRANGE <LrangeCommand.html>`_ takes two indexes, the
|
||||
first and the last element of the range to return. Both the indexes
|
||||
can be negative to tell Redis to start to count for the end, so -1
|
||||
is the last element, -2 is the penultimate element of the list, and
|
||||
so forth.
|
||||
As you can guess from the example above, lists can be used, for
|
||||
instance, in order to implement a chat system. Another use is as
|
||||
queues in order to route messages between different processes. But
|
||||
the key point is that
|
||||
**you can use Redis lists every time you require to access data in the same order they are added**.
|
||||
This will not require any SQL ORDER BY operation, will be very
|
||||
fast, and will scale to millions of elements even with a toy Linux
|
||||
box.
|
||||
For instance in ranking systems like the social news reddit.com you
|
||||
can add every new submitted link into a List, and with
|
||||
`LRANGE <LrangeCommand.html>`_ it's possible to paginate results in
|
||||
a trivial way.
|
||||
In a blog engine implementation you can have a list for every post,
|
||||
where to push blog comments, and so forth.
|
||||
Pushing IDs instead of the actual data in Redis lists
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In the above example we pushed our "objects" (simply messages in
|
||||
the example) directly inside the Redis list, but this is often not
|
||||
the way to go, as objects can be referenced in multiple times: in a
|
||||
list to preserve their chronological order, in a Set to remember
|
||||
they are about a specific category, in another list but only if
|
||||
this object matches some kind of requisite, and so forth.
|
||||
Let's return back to the reddit.com example. A more credible
|
||||
pattern for adding submitted links (news) to the list is the
|
||||
following:
|
||||
::
|
||||
|
||||
$ ./redis-cli incr next.news.id
|
||||
(integer) 1
|
||||
$ ./redis-cli set news:1:title "Redis is simple"
|
||||
OK
|
||||
$ ./redis-cli set news:1:url "http://code.google.com/p/redis"
|
||||
OK
|
||||
$ ./redis-cli lpush submitted.news 1
|
||||
OK
|
||||
|
||||
We obtained an unique incremental ID for our news object just
|
||||
incrementing a key, then used this ID to create the object setting
|
||||
a key for every field in the object. Finally the ID of the new
|
||||
object was pushed on the **submitted.news** list.
|
||||
This is just the start. Check the
|
||||
`Command Reference <CommandReference.html>`_ and read about all the
|
||||
other list related commands. You can remove elements, rotate lists,
|
||||
get and set elements by index, and of course retrieve the length of
|
||||
the list with `LLEN <LLenCommand.html>`_.
|
||||
Redis Sets
|
||||
----------
|
||||
|
||||
Redis Sets are unordered collection of binary-safe strings. The
|
||||
`SADD <SaddCommand.html>`_ command adds a new element to a set.
|
||||
It's also possible to do a number of other operations against sets
|
||||
like testing if a given element already exists, performing the
|
||||
intersection, union or difference between multiple sets and so
|
||||
forth. An example is worth 1000 words:
|
||||
::
|
||||
|
||||
$ ./redis-cli sadd myset 1
|
||||
(integer) 1
|
||||
$ ./redis-cli sadd myset 2
|
||||
(integer) 1
|
||||
$ ./redis-cli sadd myset 3
|
||||
(integer) 1
|
||||
$ ./redis-cli smembers myset
|
||||
1. 3
|
||||
2. 1
|
||||
3. 2
|
||||
|
||||
I added three elements to my set and told Redis to return back all
|
||||
the elements. As you can see they are not sorted.
|
||||
Now let's check if a given element exists:
|
||||
::
|
||||
|
||||
$ ./redis-cli sismember myset 3
|
||||
(integer) 1
|
||||
$ ./redis-cli sismember myset 30
|
||||
(integer) 0
|
||||
|
||||
"3" is a member of the set, while "30" is not. Sets are very good
|
||||
in order to express relations between objects. For instance we can
|
||||
easily use Redis Sets in order to implement tags.
|
||||
A simple way to model this is to have, for every object you want to
|
||||
tag, a Set with all the IDs of the tags associated with the object,
|
||||
and for every tag that exists, a Set of of all the objects tagged
|
||||
with this tag.
|
||||
For instance if our news ID 1000 is tagged with tag 1,2,5 and 77,
|
||||
we can specify the following two Sets:
|
||||
::
|
||||
|
||||
$ ./redis-cli sadd news:1000:tags 1
|
||||
(integer) 1
|
||||
$ ./redis-cli sadd news:1000:tags 2
|
||||
(integer) 1
|
||||
$ ./redis-cli sadd news:1000:tags 5
|
||||
(integer) 1
|
||||
$ ./redis-cli sadd news:1000:tags 77
|
||||
(integer) 1
|
||||
$ ./redis-cli sadd tag:1:objects 1000
|
||||
(integer) 1
|
||||
$ ./redis-cli sadd tag:2:objects 1000
|
||||
(integer) 1
|
||||
$ ./redis-cli sadd tag:5:objects 1000
|
||||
(integer) 1
|
||||
$ ./redis-cli sadd tag:77:objects 1000
|
||||
(integer) 1
|
||||
|
||||
To get all the tags for a given object is trivial:
|
||||
$ ./redis-cli smembers `news:1000:tags <news:1000:tags>`_ 1. 5 2. 1
|
||||
3. 77 4. 2
|
||||
But there are other non trivial operations that are still easy to
|
||||
implement using the right Redis commands. For instance we may want
|
||||
the list of all the objects having as tags 1, 2, 10, and 27 at the
|
||||
same time. We can do this using the
|
||||
`SinterCommand <SinterCommand.html>`_ that performs the
|
||||
intersection between different sets. So in order to reach our goal
|
||||
we can just use:
|
||||
::
|
||||
|
||||
$ ./redis-cli sinter tag:1:objects tag:2:objects tag:10:objects tag:27:objects
|
||||
... no result in our dataset composed of just one object ;) ...
|
||||
|
||||
Look at the `Command Reference <CommandReference.html>`_ to
|
||||
discover other Set related commands, there are a bunch of
|
||||
interesting one. Also make sure to check the
|
||||
`SORT <SortCommand.html>`_ command as both Redis Sets and Lists are
|
||||
sortable.
|
||||
A digression. How to get unique identifiers for strings
|
||||
-------------------------------------------------------
|
||||
|
||||
In our tags example we showed tag IDs without to mention how this
|
||||
IDs can be obtained. Basically for every tag added to the system,
|
||||
you need an unique identifier. You also want to be sure that there
|
||||
are no race conditions if multiple clients are trying to add the
|
||||
same tag at the same time. Also, if a tag already exists, you want
|
||||
its ID returned, otherwise a new unique ID should be created and
|
||||
associated to the tag.
|
||||
Redis 1.4 will add the Hash type. With it it will be trivial to
|
||||
associate strings with unique IDs, but how to do this today with
|
||||
the current commands exported by Redis in a reliable way?
|
||||
Our first attempt (that is broken) can be the following. Let's
|
||||
suppose we want to get an unique ID for the tag "redis":
|
||||
|
||||
- In order to make this algorithm binary safe (they are just tags
|
||||
but think to utf8, spaces and so forth) we start performing the
|
||||
SHA1 sum of the tag. SHA1(redis) =
|
||||
b840fc02d524045429941cc15f59e41cb7be6c52.
|
||||
- Let's check if this tag is already associated with an unique ID
|
||||
with the command
|
||||
**GET tag:b840fc02d524045429941cc15f59e41cb7be6c52:id**.
|
||||
- If the above GET returns an ID, return it back to the user. We
|
||||
already have the unique ID.
|
||||
- Otherwise... create a new unique ID with **INCR next.tag.id**
|
||||
(assume it returned 123456).
|
||||
- Finally associate this new ID to our tag with
|
||||
**SET tag:b840fc02d524045429941cc15f59e41cb7be6c52:id 123456** and
|
||||
return the new ID to the caller.
|
||||
|
||||
Nice. Or better.. broken! What about if two clients perform this
|
||||
commands at the same time trying to get the unique ID for the tag
|
||||
"redis"? If the timing is right they'll both get **nil** from the
|
||||
GET operation, will both increment the **next.tag.id** key and will
|
||||
set two times the key. One of the two clients will return the wrong
|
||||
ID to the caller. To fix the algorithm is not hard fortunately, and
|
||||
this is the sane version:
|
||||
|
||||
- In order to make this algorithm binary safe (they are just tags
|
||||
but think to utf8, spaces and so forth) we start performing the
|
||||
SHA1 sum of the tag. SHA1(redis) =
|
||||
b840fc02d524045429941cc15f59e41cb7be6c52.
|
||||
- Let's check if this tag is already associated with an unique ID
|
||||
with the command
|
||||
**GET tag:b840fc02d524045429941cc15f59e41cb7be6c52:id**.
|
||||
- If the above GET returns an ID, return it back to the user. We
|
||||
already have the unique ID.
|
||||
- Otherwise... create a new unique ID with **INCR next.tag.id**
|
||||
(assume it returned 123456).
|
||||
- Finally associate this new ID to our tag with
|
||||
**SETNX tag:b840fc02d524045429941cc15f59e41cb7be6c52:id 123456**.
|
||||
By using SETNX if a different client was faster than this one the
|
||||
key wil not be setted. Not only, SETNX returns 1 if the key is set,
|
||||
0 otherwise. So... let's add a final step to our computation.
|
||||
- If SETNX returned 1 (We set the key) return 123456 to the
|
||||
caller, it's our tag ID, otherwise perform
|
||||
**GET tag:b840fc02d524045429941cc15f59e41cb7be6c52:id** and return
|
||||
the value to the caller.
|
||||
|
||||
Sorted sets
|
||||
-----------
|
||||
|
||||
Sets are a very handy data type, but... they are a bit too unsorted
|
||||
in order to fit well for a number of problems ;) This is why Redis
|
||||
1.2 introduced Sorted Sets. They are very similar to Sets,
|
||||
collections of binary-safe strings, but this time with an
|
||||
associated score, and an operation similar to the List LRANGE
|
||||
operation to return items in order, but working against Sorted
|
||||
Sets, that is, the `ZRANGE <ZrangeCommand.html>`_ command.
|
||||
Basically Sorted Sets are in some way the Redis equivalent of
|
||||
Indexes in the SQL world. For instance in our reddit.com example
|
||||
above there was no mention about how to generate the actual home
|
||||
page with news raked by user votes and time. We'll see how sorted
|
||||
sets can fix this problem, but it's better to start with something
|
||||
simpler, illustrating the basic working of this advanced data type.
|
||||
Let's add a few selected hackers with their year of birth as
|
||||
"score".
|
||||
::
|
||||
|
||||
$ ./redis-cli zadd hackers 1940 "Alan Kay"
|
||||
(integer) 1
|
||||
$ ./redis-cli zadd hackers 1953 "Richard Stallman"
|
||||
(integer) 1
|
||||
$ ./redis-cli zadd hackers 1965 "Yukihiro Matsumoto"
|
||||
(integer) 1
|
||||
$ ./redis-cli zadd hackers 1916 "Claude Shannon"
|
||||
(integer) 1
|
||||
$ ./redis-cli zadd hackers 1969 "Linus Torvalds"
|
||||
(integer) 1
|
||||
$ ./redis-cli zadd hackers 1912 "Alan Turing"
|
||||
(integer) 1
|
||||
|
||||
For sorted sets it's a joke to return these hackers sorted by their
|
||||
birth year because actually **they are already sorted**. Sorted
|
||||
sets are implemented via a dual-ported data structure containing
|
||||
both a skip list and an hash table, so every time we add an element
|
||||
Redis performs an O(log(N)) operation, that's good, but when we ask
|
||||
for sorted elements Redis does not have to do any work at all, it's
|
||||
already all sorted:
|
||||
::
|
||||
|
||||
$ ./redis-cli zrange hackers 0 -1
|
||||
1. Alan Turing
|
||||
2. Claude Shannon
|
||||
3. Alan Kay
|
||||
4. Richard Stallman
|
||||
5. Yukihiro Matsumoto
|
||||
6. Linus Torvalds
|
||||
|
||||
Didn't know that Linus was younger than Yukihiro btw ;)
|
||||
Anyway I want to order this elements the other way around, using
|
||||
`ZrangeCommand <ZREVRANGE.html>`_ instead of
|
||||
`ZrangeCommand <ZRANGE.html>`_ this time:
|
||||
::
|
||||
|
||||
$ ./redis-cli zrevrange hackers 0 -1
|
||||
1. Linus Torvalds
|
||||
2. Yukihiro Matsumoto
|
||||
3. Richard Stallman
|
||||
4. Alan Kay
|
||||
5. Claude Shannon
|
||||
6. Alan Turing
|
||||
|
||||
A very important note, ZSets have just a "default" ordering but you
|
||||
are still free to call the `SORT <SortCommand.html>`_ command
|
||||
against sorted sets to get a different ordering (but this time the
|
||||
server will waste CPU). An alternative for having multiple orders
|
||||
is to add every element in multiple sorted sets at the same time.
|
||||
Operating on ranges
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Sorted sets are more powerful than this. They can operate on
|
||||
ranges. For instance let's try to get all the individuals that born
|
||||
up to the 1950. We use the
|
||||
`ZRANGEBYSCORE <ZrangebyscoreCommand.html>`_ command to do it:
|
||||
::
|
||||
|
||||
$ ./redis-cli zrangebyscore hackers -inf 1950
|
||||
1. Alan Turing
|
||||
2. Claude Shannon
|
||||
3. Alan Kay
|
||||
|
||||
We asked Redis to return all the elements with a score between
|
||||
negative infinite and 1950 (both extremes are included).
|
||||
It's also possible to remove ranges of elements. For instance let's
|
||||
remove all the hackers born between 1940 and 1960 from the sorted
|
||||
set:
|
||||
::
|
||||
|
||||
$ ./redis-cli zremrangebyscore hackers 1940 1960
|
||||
(integer) 2
|
||||
|
||||
`ZREMRANGEBYSCORE <ZremrangebyscoreCommand.html>`_ is not the best
|
||||
command name, but it can be very useful, and returns the number of
|
||||
removed elements.
|
||||
Back to the reddit example
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
For the last time, back to the Reddit example. Now we have a decent
|
||||
plan to populate a sorted set in order to generate the home page. A
|
||||
sorted set can contain all the news that are not older than a few
|
||||
days (we remove old entries from time to time using
|
||||
ZREMRANGEBYSCORE). A background job gets all the elements from this
|
||||
sorted set, get the user votes and the time of the news, and
|
||||
compute the score to populate the **reddit.home.page** sorted set
|
||||
with the news IDs and associated scores. To show the home page we
|
||||
have just to perform a blazingly fast call to ZRANGE.
|
||||
From time to time we'll remove too old news from the
|
||||
**reddit.home.page** sorted set as well in order for our system to
|
||||
work always against a limited set of news.
|
||||
Updating the scores of a sorted set
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Just a final note before to finish this tutorial. Sorted sets
|
||||
scores can be updated at any time. Just calling again ZADD against
|
||||
an element already included in the sorted set will update its score
|
||||
(and position) in O(log(N)), so sorted sets are suitable even when
|
||||
there are tons of updates.
|
||||
This tutorial is in no way complete, this is just the basics to get
|
||||
started with Redis, read the
|
||||
`Command Reference <CommandReference.html>`_ to discover a lot
|
||||
more.
|
||||
Thanks for reading. Salvatore.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,42 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**KeysCommand: Contents**
|
||||
`KEYS \_pattern\_ <#KEYS%20_pattern_>`_
|
||||
`Return value <#Return%20value>`_
|
||||
KeysCommand
|
||||
===========
|
||||
|
||||
#sidebar `GenericCommandsSidebar <GenericCommandsSidebar.html>`_
|
||||
KEYS \_pattern\_
|
||||
================
|
||||
|
||||
*Time complexity: O(n) (with n being the number of keys in the DB, and assuming keys and pattern of limited length)*
|
||||
Returns all the keys matching the glob-style *pattern* asspace
|
||||
separated strings. For example if you have in thedatabase the keys
|
||||
"foo" and "foobar" the command "KEYS foo``*``"will return "foo
|
||||
foobar".
|
||||
|
||||
Note that while the time complexity for this operation is O(n)the
|
||||
constant times are pretty low. For example Redis runningon an entry
|
||||
level laptop can scan a 1 million keys databasein 40 milliseconds.
|
||||
**Still it's better to consider this one of**
|
||||
the slow commands that may ruin the DB performance if not usedwith
|
||||
care\*.
|
||||
|
||||
In other words this command is intended only for debugging and
|
||||
\*special\* operations like creating a script to change the DB
|
||||
schema. Don't use it in your normal code. Use Redis
|
||||
`Sets <Sets.html>`_ in order to group together a subset of
|
||||
objects.
|
||||
|
||||
Glob style patterns examples:
|
||||
\* h?llo will match hello hallo hhllo\* h\*llo will match hllo
|
||||
heeeello\* h``[``ae``]``llo will match hello and hallo, but not
|
||||
hillo
|
||||
|
||||
Use \\ to escape special chars if you want to match them verbatim.
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Multi bulk reply <ReplyTypes.html>`_
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,23 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**LastsaveCommand: Contents**
|
||||
`LASTSAVE <#LASTSAVE>`_
|
||||
`Return value <#Return%20value>`_
|
||||
LastsaveCommand
|
||||
===============
|
||||
|
||||
#sidebar `ControlCommandsSidebar <ControlCommandsSidebar.html>`_
|
||||
LASTSAVE
|
||||
========
|
||||
|
||||
Return the UNIX TIME of the last DB save executed with success.A
|
||||
client may check if a `BGSAVE <BgsaveCommand.html>`_ command
|
||||
succeeded reading the LASTSAVEvalue, then issuing a
|
||||
`BGSAVE <BgsaveCommand.html>`_ command and checking at regular
|
||||
intervalsevery N seconds if LASTSAVE changed.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Integer reply <ReplyTypes.html>`_, specifically an UNIX time
|
||||
stamp.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,29 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**LindexCommand: Contents**
|
||||
`LINDEX \_key\_ \_index\_ <#LINDEX%20_key_%20_index_>`_
|
||||
`Return value <#Return%20value>`_
|
||||
LindexCommand
|
||||
=============
|
||||
|
||||
#sidebar `ListCommandsSidebar <ListCommandsSidebar.html>`_
|
||||
LINDEX \_key\_ \_index\_
|
||||
========================
|
||||
|
||||
*Time complexity: O(n) (with n being the length of the list)*
|
||||
Return the specified element of the list stored at the
|
||||
specifiedkey. 0 is the first element, 1 the second and so on.
|
||||
Negative indexesare supported, for example -1 is the last element,
|
||||
-2 the penultimateand so on.
|
||||
|
||||
If the value stored at key is not of list type an error is
|
||||
returned.If the index is out of range a 'nil' reply is returned.
|
||||
|
||||
Note that even if the average time complexity is O(n) asking forthe
|
||||
first or the last element of the list is O(1).
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Bulk reply <ReplyTypes.html>`_, specifically the requested
|
||||
element.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,24 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**ListCommandsSidebar: Contents**
|
||||
ListCommandsSidebar
|
||||
===================
|
||||
|
||||
== List Commands ==
|
||||
|
||||
- `RPUSH <RpushCommand.html>`_
|
||||
- `LPUSH <RpushCommand.html>`_
|
||||
- `LLEN <LlenCommand.html>`_
|
||||
- `LRANGE <LrangeCommand.html>`_
|
||||
- `LTRIM <LtrimCommand.html>`_
|
||||
- `LINDEX <LindexCommand.html>`_
|
||||
- `LSET <LsetCommand.html>`_
|
||||
- `LREM <LremCommand.html>`_
|
||||
- `LPOP <LpopCommand.html>`_
|
||||
- `RPOP <LpopCommand.html>`_
|
||||
- `BLPOP <BlpopCommand.html>`_
|
||||
- `BRPOP <BlpopCommand.html>`_
|
||||
- `RPOPLPUSH <RpoplpushCommand.html>`_
|
||||
- `BRPOPLPUSH <BrpoplpushCommand.html>`_
|
||||
- `SORT <SortCommand.html>`_
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,43 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**Lists: Contents**
|
||||
`Redis List Type <#Redis%20List%20Type>`_
|
||||
`Implementation details <#Implementation%20details>`_
|
||||
Lists
|
||||
=====
|
||||
|
||||
#sidebar `ListCommandsSidebar <ListCommandsSidebar.html>`_
|
||||
Redis List Type
|
||||
===============
|
||||
|
||||
Redis Lists are lists of `Redis Strings <Strings.html>`_, sorted by
|
||||
insertion order. It's possible to add elements to a Redis List
|
||||
pushing new elements on the head (on the left) or on the tail (on
|
||||
the right) of the list.
|
||||
The `LPUSH <RpushCommand.html>`_ command inserts a new elmenet on
|
||||
head, while `RPUSH <RpushCommand.html>`_ inserts a new element on
|
||||
tail. A new list is created when one of this operations is
|
||||
performed against an empty key.
|
||||
For instance if perform the following operations:
|
||||
::
|
||||
|
||||
LPUSH mylist a # now the list is "a"
|
||||
LPUSH mylist b # now the list is "b","a"
|
||||
RPUSH mylist c # now the list is "b","a","c" (RPUSH was used this time)
|
||||
|
||||
The resulting list stored at *mylist* will contain the elements
|
||||
"b","a","c".
|
||||
The max length of a list is 232-1 elements (4294967295, more than 4
|
||||
billion of elements per list).
|
||||
Implementation details
|
||||
======================
|
||||
|
||||
Redis Lists are implemented as doubly liked lists. A few commands
|
||||
benefit from the fact the lists are doubly linked in order to reach
|
||||
the needed element starting from the nearest extreme (head or
|
||||
tail). `LRANGE <LrangeCommand.html>`_ and
|
||||
`LINDEX <LindexCommand.html>`_ are examples of such commands.
|
||||
The use of linked lists also guarantees that regardless of the
|
||||
length of the list pushing and popping are O(1) operations.
|
||||
Redis Lists cache length information so `LLEN <LlenCommand.html>`_
|
||||
is O(1) as well.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,26 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**LlenCommand: Contents**
|
||||
`LLEN \_key\_ <#LLEN%20_key_>`_
|
||||
`Return value <#Return%20value>`_
|
||||
LlenCommand
|
||||
===========
|
||||
|
||||
#sidebar `ListCommandsSidebar <ListCommandsSidebar.html>`_
|
||||
LLEN \_key\_
|
||||
============
|
||||
|
||||
*Time complexity: O(1)*
|
||||
Return the length of the list stored at the specified key. If
|
||||
thekey does not exist zero is returned (the same behaviour as
|
||||
forempty lists). If the value stored at *key* is not a list an
|
||||
error is returned.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Integer reply <ReplyTypes.html>`_, specifically:
|
||||
::
|
||||
|
||||
The length of the list.
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,28 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**LpopCommand: Contents**
|
||||
`LPOP \_key\_ <#LPOP%20_key_>`_
|
||||
`RPOP \_key\_ <#RPOP%20_key_>`_
|
||||
`Return value <#Return%20value>`_
|
||||
LpopCommand
|
||||
===========
|
||||
|
||||
#sidebar `ListCommandsSidebar <ListCommandsSidebar.html>`_
|
||||
LPOP \_key\_
|
||||
============
|
||||
|
||||
RPOP \_key\_
|
||||
============
|
||||
|
||||
*Time complexity: O(1)*
|
||||
Atomically return and remove the first (LPOP) or last (RPOP)
|
||||
elementof the list. For example if the list contains the elements
|
||||
"a","b","c" LPOPwill return "a" and the list will become "b","c".
|
||||
|
||||
If the *key* does not exist or the list is already empty the
|
||||
specialvalue 'nil' is returned.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Bulk reply <ReplyTypes.html>`_
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,44 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**LrangeCommand: Contents**
|
||||
`LRANGE \_key\_ \_start\_ \_end\_ <#LRANGE%20_key_%20_start_%20_end_>`_
|
||||
`Consistency with range functions in various programming languages <#Consistency%20with%20range%20functions%20in%20various%20programming%20languages>`_
|
||||
`Out-of-range indexes <#Out-of-range%20indexes>`_
|
||||
`Return value <#Return%20value>`_
|
||||
LrangeCommand
|
||||
=============
|
||||
|
||||
#sidebar `ListCommandsSidebar <ListCommandsSidebar.html>`_
|
||||
LRANGE \_key\_ \_start\_ \_end\_
|
||||
================================
|
||||
|
||||
*Time complexity: O(start+n) (with n being the length of the range and start being the start offset)*Return
|
||||
the specified elements of the list stored at the specified key.
|
||||
Start and end are zero-based indexes. 0 is the first element of the
|
||||
list (the list head), 1 the next element and so on.
|
||||
For example LRANGE foobar 0 2 will return the first three elements
|
||||
of the list.
|
||||
*start* and *end* can also be negative numbers indicating offsets
|
||||
from the end of the list. For example -1 is the last element of the
|
||||
list, -2 the penultimate element and so on.
|
||||
Consistency with range functions in various programming languages
|
||||
-----------------------------------------------------------------
|
||||
|
||||
Note that if you have a list of numbers from 0 to 100, LRANGE 0 10
|
||||
will return 11 elements, that is, rightmost item is included. This
|
||||
**may or may not** be consistent with behavior of range-related
|
||||
functions in your programming language of choice (think Ruby's
|
||||
Range.new, Array#slice or Python's range() function).
|
||||
LRANGE behavior is consistent with one of Tcl.
|
||||
Out-of-range indexes
|
||||
--------------------
|
||||
|
||||
Indexes out of range will not produce an error: if start is over
|
||||
the end of the list, or start ``>`` end, an empty list is returned.
|
||||
If end is over the end of the list Redis will threat it just like
|
||||
the last element of the list.
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Multi bulk reply <ReplyTypes.html>`_, specifically a list of
|
||||
elements in the specified range.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,32 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**LremCommand: Contents**
|
||||
`LREM \_key\_ \_count\_ \_value\_ <#LREM%20_key_%20_count_%20_value_>`_
|
||||
`Return value <#Return%20value>`_
|
||||
LremCommand
|
||||
===========
|
||||
|
||||
#sidebar `ListCommandsSidebar <ListCommandsSidebar.html>`_
|
||||
LREM \_key\_ \_count\_ \_value\_
|
||||
================================
|
||||
|
||||
*Time complexity: O(N) (with N being the length of the list)*
|
||||
Remove the first *count* occurrences of the *value* element from
|
||||
the list.If *count* is zero all the elements are removed. If
|
||||
*count* is negativeelements are removed from tail to head, instead
|
||||
to go from head to tailthat is the normal behaviour. So for example
|
||||
LREM with count -2 and\_hello\_ as value to remove against the list
|
||||
(a,b,c,hello,x,hello,hello) willlave the list (a,b,c,hello,x). The
|
||||
number of removed elements is returnedas an integer, see below for
|
||||
more information about the returned value.Note that non existing
|
||||
keys are considered like empty lists by LREM, so LREMagainst non
|
||||
existing keys will always return 0.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Integer Reply <ReplyTypes.html>`_, specifically:
|
||||
::
|
||||
|
||||
The number of removed elements if the operation succeeded
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,26 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**LsetCommand: Contents**
|
||||
`LSET \_key\_ \_index\_ \_value\_ <#LSET%20_key_%20_index_%20_value_>`_
|
||||
`Return value <#Return%20value>`_
|
||||
LsetCommand
|
||||
===========
|
||||
|
||||
#sidebar `ListCommandsSidebar <ListCommandsSidebar.html>`_
|
||||
LSET \_key\_ \_index\_ \_value\_
|
||||
================================
|
||||
|
||||
*Time complexity: O(N) (with N being the length of the list)*
|
||||
Set the list element at *index* (see LINDEX for information about
|
||||
the\_index\_ argument) with the new *value*. Out of range indexes
|
||||
willgenerate an error. Note that setting the first or last elements
|
||||
ofthe list is O(1).
|
||||
|
||||
Similarly to other list commands accepting indexes, the index can
|
||||
be negative to access elements starting from the end of the list.
|
||||
So -1 is the last element, -2 is the penultimate, and so forth.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Status code reply <ReplyTypes.html>`_
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,49 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**LtrimCommand: Contents**
|
||||
`LTRIM \_key\_ \_start\_ \_end\_ <#LTRIM%20_key_%20_start_%20_end_>`_
|
||||
`Return value <#Return%20value>`_
|
||||
LtrimCommand
|
||||
============
|
||||
|
||||
#sidebar `ListCommandsSidebar <ListCommandsSidebar.html>`_
|
||||
LTRIM \_key\_ \_start\_ \_end\_
|
||||
===============================
|
||||
|
||||
*Time complexity: O(n) (with n being len of list - len of range)*
|
||||
Trim an existing list so that it will contain only the
|
||||
specifiedrange of elements specified. Start and end are zero-based
|
||||
indexes.0 is the first element of the list (the list head), 1 the
|
||||
next elementand so on.
|
||||
|
||||
For example LTRIM foobar 0 2 will modify the list stored at
|
||||
foobarkey so that only the first three elements of the list will
|
||||
remain.
|
||||
|
||||
\_start\_ and *end* can also be negative numbers indicating
|
||||
offsetsfrom the end of the list. For example -1 is the last element
|
||||
ofthe list, -2 the penultimate element and so on.
|
||||
|
||||
Indexes out of range will not produce an error: if start is overthe
|
||||
end of the list, or start > end, an empty list is left as value.If
|
||||
end over the end of the list Redis will threat it just likethe last
|
||||
element of the list.
|
||||
|
||||
Hint: the obvious use of LTRIM is together with LPUSH/RPUSH. For
|
||||
example:
|
||||
|
||||
::
|
||||
|
||||
LPUSH mylist <someelement>
|
||||
LTRIM mylist 0 99
|
||||
|
||||
The above two commands will push elements in the list taking care
|
||||
thatthe list will not grow without limits. This is very useful when
|
||||
usingRedis to store logs for example. It is important to note that
|
||||
when usedin this way LTRIM is an O(1) operation because in the
|
||||
average casejust one element is removed from the tail of the list.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Status code reply <ReplyTypes.html>`_
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,40 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**MgetCommand: Contents**
|
||||
`MGET \_key1\_ \_key2\_ ... \_keyN\_ <#MGET%20_key1_%20_key2_%20...%20_keyN_>`_
|
||||
`Return value <#Return%20value>`_
|
||||
`Example <#Example>`_
|
||||
MgetCommand
|
||||
===========
|
||||
|
||||
#sidebar `StringCommandsSidebar <StringCommandsSidebar.html>`_
|
||||
MGET \_key1\_ \_key2\_ ... \_keyN\_
|
||||
===================================
|
||||
|
||||
*Time complexity: O(1) for every key*
|
||||
Get the values of all the specified keys. If one or more keys dont
|
||||
existor is not of type String, a 'nil' value is returned instead of
|
||||
the valueof the specified key, but the operation never fails.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Multi bulk reply <ReplyTypes.html>`_
|
||||
Example
|
||||
-------
|
||||
|
||||
::
|
||||
|
||||
$ ./redis-cli set foo 1000
|
||||
+OK
|
||||
$ ./redis-cli set bar 2000
|
||||
+OK
|
||||
$ ./redis-cli mget foo bar
|
||||
1. 1000
|
||||
2. 2000
|
||||
$ ./redis-cli mget foo bar nokey
|
||||
1. 1000
|
||||
2. 2000
|
||||
3. (nil)
|
||||
$
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,54 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**MonitorCommand: Contents**
|
||||
`MONITOR <#MONITOR>`_
|
||||
`Return value <#Return%20value>`_
|
||||
MonitorCommand
|
||||
==============
|
||||
|
||||
#sidebar `ControlCommandsSidebar <ControlCommandsSidebar.html>`_
|
||||
MONITOR
|
||||
=======
|
||||
|
||||
MONITOR is a debugging command that outputs the whole sequence of
|
||||
commandsreceived by the Redis server. is very handy in order to
|
||||
understandwhat is happening into the database. This command is used
|
||||
directlyvia telnet.
|
||||
|
||||
::
|
||||
|
||||
% telnet 127.0.0.1 6379
|
||||
Trying 127.0.0.1...
|
||||
Connected to segnalo-local.com.
|
||||
Escape character is '^]'.
|
||||
MONITOR
|
||||
+OK
|
||||
monitor
|
||||
keys *
|
||||
dbsize
|
||||
set x 6
|
||||
foobar
|
||||
get x
|
||||
del x
|
||||
get x
|
||||
set key_x 5
|
||||
hello
|
||||
set key_y 5
|
||||
hello
|
||||
set key_z 5
|
||||
hello
|
||||
set foo_a 5
|
||||
hello
|
||||
|
||||
The ability to see all the requests processed by the server is
|
||||
useful in orderto spot bugs in the application both when using
|
||||
Redis as a database and asa distributed caching system.
|
||||
|
||||
In order to end a monitoring session just issue a QUIT command by
|
||||
hand.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
**Non standard return value**, just dumps the received commands in
|
||||
an infinite flow.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,27 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**MoveCommand: Contents**
|
||||
`MOVE \_key\_ \_dbindex\_ <#MOVE%20_key_%20_dbindex_>`_
|
||||
`Return value <#Return%20value>`_
|
||||
MoveCommand
|
||||
===========
|
||||
|
||||
#sidebar `GenericCommandsSidebar <GenericCommandsSidebar.html>`_
|
||||
MOVE \_key\_ \_dbindex\_
|
||||
========================
|
||||
|
||||
Move the specified key from the currently selected DB to the
|
||||
specifieddestination DB. Note that this command returns 1 only if
|
||||
the key wassuccessfully moved, and 0 if the target key was already
|
||||
there or if thesource key was not found at all, so it is possible
|
||||
to use MOVE as a lockingprimitive.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Integer reply <ReplyTypes.html>`_, specifically:
|
||||
::
|
||||
|
||||
1 if the key was moved
|
||||
0 if the key was not moved because already present on the target DB or was not found in the current DB.
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,47 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**MsetCommand: Contents**
|
||||
`MSET \_key1\_ \_value1\_ \_key2\_ \_value2\_ ... \_keyN\_ \_valueN\_ (Redis > <#MSET%20_key1_%20_value1_%20_key2_%20_value2_%20...%20_keyN_%20_valueN_%20(Redis%20%3E>`_
|
||||
`MSETNX \_key1\_ \_value1\_ \_key2\_ \_value2\_ ... \_keyN\_ \_valueN\_ (Redis > <#MSETNX%20_key1_%20_value1_%20_key2_%20_value2_%20...%20_keyN_%20_valueN_%20(Redis%20%3E>`_
|
||||
`MSET Return value <#MSET%20Return%20value>`_
|
||||
`MSETNX Return value <#MSETNX%20Return%20value>`_
|
||||
MsetCommand
|
||||
===========
|
||||
|
||||
#sidebar `StringCommandsSidebar <StringCommandsSidebar.html>`_
|
||||
MSET \_key1\_ \_value1\_ \_key2\_ \_value2\_ ... \_keyN\_ \_valueN\_ (Redis >
|
||||
=============================================================================
|
||||
|
||||
1.1) =
|
||||
MSETNX \_key1\_ \_value1\_ \_key2\_ \_value2\_ ... \_keyN\_ \_valueN\_ (Redis >
|
||||
===============================================================================
|
||||
|
||||
1.1) = *Time complexity: O(1) to set every key*
|
||||
Set the the respective keys to the respective values. MSET will
|
||||
replace oldvalues with new values, while MSETNX will not perform
|
||||
any operation at alleven if just a single key already exists.
|
||||
|
||||
Because of this semantic MSETNX can be used in order to set
|
||||
different keysrepresenting different fields of an unique logic
|
||||
object in a way thatensures that either all the fields or none at
|
||||
all are set.
|
||||
|
||||
Both MSET and MSETNX are atomic operations. This means that for
|
||||
instanceif the keys A and B are modified, another client talking to
|
||||
Redis can eithersee the changes to both A and B at once, or no
|
||||
modification at all.
|
||||
|
||||
MSET Return value
|
||||
-----------------
|
||||
|
||||
`Status code reply <ReplyTypes.html>`_ Basically +OK as MSET can't
|
||||
fail
|
||||
MSETNX Return value
|
||||
-------------------
|
||||
|
||||
`Integer reply <ReplyTypes.html>`_, specifically:
|
||||
::
|
||||
|
||||
1 if the all the keys were set
|
||||
0 if no key was set (at least one key already existed)
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,253 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**MultiExecCommand: Contents**
|
||||
`WATCH key1 key2 ... keyN (Redis > <#WATCH%20key1%20key2%20...%20keyN%20(Redis%20%3E>`_
|
||||
`UNWATCH <#UNWATCH>`_
|
||||
`MULTI <#MULTI>`_
|
||||
`COMMAND\_1 ... <#COMMAND_1%20...>`_
|
||||
`COMMAND\_2 ... <#COMMAND_2%20...>`_
|
||||
`COMMAND\_N ... <#COMMAND_N%20...>`_
|
||||
`EXEC or DISCARD <#EXEC%20or%20DISCARD>`_
|
||||
`Usage <#Usage>`_
|
||||
`The DISCARD command <#The%20DISCARD%20command>`_
|
||||
`Check and Set (CAS) transactions using WATCH <#Check%20and%20Set%20(CAS)%20transactions%20using%20WATCH>`_
|
||||
`WATCH explained <#WATCH%20explained>`_
|
||||
`WATCH used to implement ZPOP <#WATCH%20used%20to%20implement%20ZPOP>`_
|
||||
`Return value <#Return%20value>`_
|
||||
MultiExecCommand
|
||||
================
|
||||
|
||||
#sidebar `GenericCommandsSidebar <GenericCommandsSidebar.html>`_
|
||||
WATCH key1 key2 ... keyN (Redis >
|
||||
=================================
|
||||
|
||||
2.1.0)=
|
||||
UNWATCH
|
||||
=======
|
||||
|
||||
MULTI
|
||||
=====
|
||||
|
||||
COMMAND\_1 ...
|
||||
==============
|
||||
|
||||
COMMAND\_2 ...
|
||||
==============
|
||||
|
||||
COMMAND\_N ...
|
||||
==============
|
||||
|
||||
EXEC or DISCARD
|
||||
===============
|
||||
|
||||
MULTI, EXEC, DISCARD and WATCH commands are the foundation of Redis
|
||||
Transactions. A Redis Transaction allows the execution of a group
|
||||
of Redis commands in a single step, with two important guarantees:
|
||||
|
||||
- All the commands in a transaction are serialized and executed
|
||||
sequentially. It can never happen that a request issued by another
|
||||
client is served **in the middle** of the execution of a Redis
|
||||
transaction. This guarantees that the commands are executed as a
|
||||
single atomic operation.
|
||||
- Either all of the commands or none are processed. The EXEC
|
||||
command triggers the execution of all the commands in the
|
||||
transaction, so if a client loses the connection to the server in
|
||||
the context of a transaction before calling the MULTI command none
|
||||
of the operations are performed, instead if the EXEC command is
|
||||
called, all the operations are performed. An exception to this rule
|
||||
is when the Append Only File is enabled: every command that is part
|
||||
of a Redis transaction will log in the AOF as long as the operation
|
||||
is completed, so if the Redis server crashes or is killed by the
|
||||
system administrator in some hard way it is possible that only a
|
||||
partial number of operations are registered.
|
||||
|
||||
Since Redis 2.1.0, it's also possible to add a further guarantee to
|
||||
the above two, in the form of optimistic locking of a set of keys
|
||||
in a way very similar to a CAS (check and set) operation. This is
|
||||
documented later in this manual page.
|
||||
Usage
|
||||
-----
|
||||
|
||||
A Redis transaction is entered using the MULTI command. The command
|
||||
always replies with OK. At this point the user can issue multiple
|
||||
commands. Instead of executing these commands, Redis will "queue"
|
||||
them. All the commands are executed once EXEC is called.
|
||||
Calling DISCARD instead will flush the transaction queue and will
|
||||
exit the transaction.
|
||||
The following is an example using the Ruby client:
|
||||
::
|
||||
|
||||
?> r.multi
|
||||
=> "OK"
|
||||
>> r.incr "foo"
|
||||
=> "QUEUED"
|
||||
>> r.incr "bar"
|
||||
=> "QUEUED"
|
||||
>> r.incr "bar"
|
||||
=> "QUEUED"
|
||||
>> r.exec
|
||||
=> [1, 1, 2]
|
||||
|
||||
As it is possible to see from the session above, MULTI returns an
|
||||
"array" of replies, where every element is the reply of a single
|
||||
command in the transaction, in the same order the commands were
|
||||
queued.
|
||||
When a Redis connection is in the context of a MULTI request, all
|
||||
the commands will reply with a simple string "QUEUED" if they are
|
||||
correct from the point of view of the syntax and arity (number of
|
||||
arguments) of the commaand. Some commands are still allowed to fail
|
||||
during execution time.
|
||||
This is more clear on the protocol level; In the following example
|
||||
one command will fail when executed even if the syntax is right:
|
||||
::
|
||||
|
||||
Trying 127.0.0.1...
|
||||
Connected to localhost.
|
||||
Escape character is '^]'.
|
||||
MULTI
|
||||
+OK
|
||||
SET a 3
|
||||
abc
|
||||
+QUEUED
|
||||
LPOP a
|
||||
+QUEUED
|
||||
EXEC
|
||||
*2
|
||||
+OK
|
||||
-ERR Operation against a key holding the wrong kind of value
|
||||
|
||||
MULTI returned a two elements bulk reply where one is an +OK code
|
||||
and one is a -ERR reply. It's up to the client lib to find a
|
||||
sensible way to provide the error to the user.
|
||||
IMPORTANT: even when a command will raise an error, all the other
|
||||
commandsin the queue will be processed. Redis will NOT stop the
|
||||
processing ofcommands once an error is found.
|
||||
|
||||
Another example, again using the write protocol with telnet, shows
|
||||
how syntax errors are reported ASAP instead:
|
||||
::
|
||||
|
||||
MULTI
|
||||
+OK
|
||||
INCR a b c
|
||||
-ERR wrong number of arguments for 'incr' command
|
||||
|
||||
This time due to the syntax error the "bad" INCR command is not
|
||||
queued at all.
|
||||
The DISCARD command
|
||||
-------------------
|
||||
|
||||
DISCARD can be used in order to abort a transaction. No command
|
||||
will be executed, and the state of the client is again the normal
|
||||
one, outside of a transaction. Example using the Ruby client:
|
||||
::
|
||||
|
||||
?> r.set("foo",1)
|
||||
=> true
|
||||
>> r.multi
|
||||
=> "OK"
|
||||
>> r.incr("foo")
|
||||
=> "QUEUED"
|
||||
>> r.discard
|
||||
=> "OK"
|
||||
>> r.get("foo")
|
||||
=> "1"
|
||||
|
||||
Check and Set (CAS) transactions using WATCH
|
||||
--------------------------------------------
|
||||
|
||||
WATCH is used in order to provide a CAS (Check and Set) behavior to
|
||||
Redis Transactions.
|
||||
WATCHed keys are monitored in order to detect changes against this
|
||||
keys. If at least a watched key will be modified before the EXEC
|
||||
call, the whole transaction will abort, and EXEC will return a nil
|
||||
object (A Null Multi Bulk reply) to notify that the transaction
|
||||
failed.
|
||||
For example imagine we have the need to atomically increment the
|
||||
value of a key by 1 (I know we have INCR, let's suppose we don't
|
||||
have it).
|
||||
The first try may be the following:
|
||||
::
|
||||
|
||||
val = GET mykey
|
||||
val = val + 1
|
||||
SET mykey $val
|
||||
|
||||
This will work reliably only if we have a single client performing
|
||||
the operation in a given time. If multiple clients will try to
|
||||
increment the key about at the same time there will be a race
|
||||
condition. For instance client A and B will read the old value, for
|
||||
instance, 10. The value will be incremented to 11 by both the
|
||||
clients, and finally SET as the value of the key. So the final
|
||||
value will be "11" instead of "12".
|
||||
Thanks to WATCH we are able to model the problem very well:
|
||||
::
|
||||
|
||||
WATCH mykey
|
||||
val = GET mykey
|
||||
val = val + 1
|
||||
MULTI
|
||||
SET mykey $val
|
||||
EXEC
|
||||
|
||||
Using the above code, if there are race conditions and another
|
||||
client modified the result of *val* in the time between our call to
|
||||
WATCH and our call to EXEC, the transaction will fail.
|
||||
We'll have just to re-iterate the operation hoping this time we'll
|
||||
not get a new race. This form of locking is called
|
||||
**optimistic locking** and is a very powerful form of locking as in
|
||||
many problems there are multiple clients accessing a much bigger
|
||||
number of keys, so it's very unlikely that there are collisions:
|
||||
usually operations don't need to be performed multiple times.
|
||||
WATCH explained
|
||||
---------------
|
||||
|
||||
So what is WATCH really about? It is a command that will make the
|
||||
EXEC conditional: we are asking Redis to perform the transaction
|
||||
only if no other client modified any of the WATCHed keys. Otherwise
|
||||
the transaction is not entered at all. (Note that if you WATCH a
|
||||
volatile key and Redis expires the key after you WATCHed it, EXEC
|
||||
will still work.
|
||||
`More <http://code.google.com/p/redis/issues/detail?id=270>`_.)
|
||||
WATCH can be called multiple times. Simply all the WATCH calls will
|
||||
have the effects to watch for changes starting from the call, up to
|
||||
the moment EXEC is called.
|
||||
When EXEC is called, either if it will fail or succeed, all keys
|
||||
are UNWATCHed. Also when a client connection is closed, everything
|
||||
gets UNWATCHed.
|
||||
It is also possible to use the UNWATCH command (without arguments)
|
||||
in order to flush all the watched keys. Sometimes this is useful as
|
||||
we optimistically lock a few keys, since possibly we need to
|
||||
perform a transaction to alter those keys, but after reading the
|
||||
current content of the keys we don't want to proceed. When this
|
||||
happens we just call UNWATCH so that the connection can already be
|
||||
used freely for new transactions.
|
||||
WATCH used to implement ZPOP
|
||||
----------------------------
|
||||
|
||||
A good example to illustrate how WATCH can be used to create new
|
||||
atomic operations otherwise not supported by Redis is to implement
|
||||
ZPOP, that is a command that pops the element with the lower score
|
||||
from a sorted set in an atomic way. This is the simplest
|
||||
implementation:
|
||||
::
|
||||
|
||||
WATCH zset
|
||||
ele = ZRANGE zset 0 0
|
||||
MULTI
|
||||
ZREM zset ele
|
||||
EXEC
|
||||
|
||||
If EXEC fails (returns a nil value) we just re-iterate the
|
||||
operation.
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Multi bulk reply <ReplyTypes.html>`_, specifically:
|
||||
::
|
||||
|
||||
The result of a MULTI/EXEC command is a multi bulk reply where every element is the return value of every command in the atomic transaction.
|
||||
|
||||
If a MULTI/EXEC transaction is aborted because of WATCH detected
|
||||
modified keys, a `Null Multi Bulk reply <ReplyTypes.html>`_ is
|
||||
returned.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,48 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**NonexistentCommands: Contents**
|
||||
`HGETSET <#HGETSET>`_
|
||||
`SET with expire <#SET%20with%20expire>`_
|
||||
`ZADDNX <#ZADDNX>`_
|
||||
NonexistentCommands
|
||||
===================
|
||||
|
||||
A list of commands that don't exist in Redis, but can be
|
||||
accomplished in a different way.
|
||||
This is a list of commands that don't exist in Redis, but can be
|
||||
accomplished in a different way, usually by means of
|
||||
`WATCH/MULTI/EXEC <MultiExecCommand.html>`_.
|
||||
For better performance, you can pipeline multiple commands.
|
||||
HGETSET
|
||||
=======
|
||||
|
||||
`GETSET <GetsetCommand.html>`_ for Hashes.
|
||||
::
|
||||
|
||||
WATCH foo
|
||||
old_value = HGET foo field
|
||||
MULTI
|
||||
HSET foo field new_value
|
||||
EXEC
|
||||
|
||||
SET with expire
|
||||
===============
|
||||
|
||||
See `SETEX <SetexCommand.html>`_.
|
||||
ZADDNX
|
||||
======
|
||||
|
||||
Add an element to a sorted set, only if the element doesn't already
|
||||
exist (by default, `ZADD <ZaddCommand.html>`_ would update the
|
||||
element's score if it already exists).
|
||||
`See thread <http://groups.google.com/group/redis-db/browse_thread/thread/fc4c79d72e5bd346/6cdc07ecc36b81e7>`_.
|
||||
::
|
||||
|
||||
WATCH foo
|
||||
score = ZSCORE foo bar
|
||||
IF score != NIL
|
||||
MULTI
|
||||
ZADD foo 1 bar
|
||||
EXEC
|
||||
ENDIF
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,59 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**ObjectHashMappers: Contents**
|
||||
`Object Hash Mappers <#Object%20Hash%20Mappers>`_
|
||||
`Ruby <#Ruby>`_
|
||||
`Ohm <#Ohm>`_
|
||||
`dm-redis-adapter <#dm-redis-adapter>`_
|
||||
`redis-models <#redis-models>`_
|
||||
ObjectHashMappers
|
||||
=================
|
||||
|
||||
Object Hash Mappers
|
||||
===================
|
||||
|
||||
Looking for a higher level if abstraction for your Objects, their
|
||||
Properties and Relationships?
|
||||
There is not need to stick to the
|
||||
`client libraries <SupportedLanguages.html>`_ exposing the raw
|
||||
features of Redis, here you will find a list of
|
||||
**Object Hash Mappers**, working in the same fashion a ORM does.
|
||||
Ruby
|
||||
----
|
||||
|
||||
Ohm
|
||||
~~~
|
||||
|
||||
|
||||
- Object-hash mapping library for Redis. It includes an extensible
|
||||
list of validations and has very good performance.
|
||||
- Authors: `Michel Martens <http://soveran.com/>`_,
|
||||
`@soveran <http://twitter.com/soveran>`_; and Damian Janowski
|
||||
`@djanowski <http://twitter.com/djanowski>`_.
|
||||
- Repository:
|
||||
`http://github.com/soveran/ohm <http://github.com/soveran/ohm>`_
|
||||
- Group:
|
||||
`http://groups.google.com/group/ohm-ruby <http://groups.google.com/group/ohm-ruby>`_
|
||||
|
||||
dm-redis-adapter
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
- This is a DataMapper (ORM that is based on the IdentityMap
|
||||
pattern) adapter for the Redis key-value database.
|
||||
- Author: `Whoahbot <http://whoahbot.com/>`_,
|
||||
`@whoahbot <http://twitter.com/whoahbot>`_.
|
||||
- Repository:
|
||||
`http://github.com/whoahbot/dm-redis-adapter/ <http://github.com/whoahbot/dm-redis-adapter/>`_
|
||||
|
||||
redis-models
|
||||
~~~~~~~~~~~~
|
||||
|
||||
|
||||
- Minimal model support for Redis. Directly maps Ruby properties
|
||||
to model\_name:id:field\_name keys in redis. Scalar, List and Set
|
||||
properties are supported. Values can be marshaled to/from Integer,
|
||||
Float, DateTime, JSON.
|
||||
- Repository:
|
||||
`http://github.com/voloko/redis-model <http://github.com/voloko/redis-model>`_
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,28 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**Pipelining: Contents**
|
||||
`Pipelining (DRAFT) <#Pipelining%20(DRAFT)>`_
|
||||
Pipelining
|
||||
==========
|
||||
|
||||
Pipelining (DRAFT)
|
||||
==================
|
||||
|
||||
A client library can use the same connection in order to issue
|
||||
multiple commands. But Redis supports **pipelining**, so multiple
|
||||
commands can be sent to the server with a single write operation by
|
||||
the client, without need to read the server reply in order to issue
|
||||
the next command. All the replies can be read at the end.
|
||||
Usually Redis server and client will have a very fast link so this
|
||||
is not very important to support this feature in a client
|
||||
implementation, still if an application needs to issue a very large
|
||||
number of commands in s short time, using pipelining can be much
|
||||
faster.
|
||||
Please read the
|
||||
`ProtocolSpecification <ProtocolSpecification.html>`_ if you want
|
||||
to learn more about the way Redis
|
||||
`clients <SupportedLanguages.html>`_ and the server communicate.
|
||||
Pipelining is one of the `Speed <Speed.html>`_
|
||||
`Features <Features.html>`_ of Redis, you can also check the
|
||||
support for
|
||||
`send and receive multiple values in a single command <MultiBulkCommands.html>`_.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,95 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**ProgrammingExamples: Contents**
|
||||
`Programming Examples (DRAFT) <#Programming%20Examples%20(DRAFT)>`_
|
||||
`TODO <#TODO>`_
|
||||
`Java <#Java>`_
|
||||
`Twayis <#Twayis>`_
|
||||
`PHP <#PHP>`_
|
||||
`Retwis <#Retwis>`_
|
||||
`Ruby <#Ruby>`_
|
||||
`twatcher-lite <#twatcher-lite>`_
|
||||
`Resque <#Resque>`_
|
||||
`Retwis-rb <#Retwis-rb>`_
|
||||
`scanty-redis <#scanty-redis>`_
|
||||
`Note Taking <#Note%20Taking>`_
|
||||
ProgrammingExamples
|
||||
===================
|
||||
|
||||
Programming Examples (DRAFT)
|
||||
============================
|
||||
|
||||
TODO
|
||||
----
|
||||
|
||||
|
||||
- Add
|
||||
`http://github.com/jodosha/redis-store <http://github.com/jodosha/redis-store>`_
|
||||
|
||||
Nothing speaks better than code examples, here you are:
|
||||
Java
|
||||
----
|
||||
|
||||
Twayis
|
||||
~~~~~~
|
||||
|
||||
A Java clone of **Retwis** showcase integration between the
|
||||
`Play! framework <http://www.playframework.org/>`_ and Redis
|
||||
`Google Code Project Page <http://code.google.com/p/twayis/>`_
|
||||
PHP
|
||||
---
|
||||
|
||||
Retwis
|
||||
~~~~~~
|
||||
|
||||
A PHP Twitter clone, the original example of Redis capabilities.
|
||||
With a `live demo <http://retwis.antirez.com/>`_, and an
|
||||
`article explaining it design <http://code.google.com/p/redis/wiki/TwitterAlikeExample>`_.
|
||||
You can find the code in the Downloads tab.
|
||||
Ruby
|
||||
----
|
||||
|
||||
twatcher-lite
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
A simplied version of the application running
|
||||
`http://twatcher.com/ <http://twatcher.com/>`_ from Mirko Froehlich
|
||||
(`@digitalhobbit <http://twitter.com/digitalhobbit>`_) with a full
|
||||
blog post explaining its development at
|
||||
`Building a Twitter Filter With Sinatra, Redis, and TweetStream <http://www.digitalhobbit.com/2009/11/08/building-a-twitter-filter-with-sinatra-redis-and-tweetstream/>`_
|
||||
Resque
|
||||
~~~~~~
|
||||
|
||||
The "simple" Redis-based queue behind Github background jobs, that
|
||||
replaced SQS, Starling, ActiveMessaging, BackgroundJob, DelayedJob,
|
||||
and Beanstalkd. Developed by Chris Wanstrath
|
||||
(`@defunkt <http://twitter.com/defunkt>`_) the code is at
|
||||
`http://github.com/defunkt/resque <http://github.com/defunkt/resque>`_,
|
||||
be sure to read
|
||||
`the introduction <http://github.com/blog/542-introducing-resque>`_
|
||||
Retwis-rb
|
||||
~~~~~~~~~
|
||||
|
||||
A port of **Retwis** to Ruby and
|
||||
`Sinatra <http://www.sinatrarb.com/>`_ written by Daniel Lucraft
|
||||
(`@DanLucraft <http://twitter.com/DanLucraft>`_) Full source code
|
||||
is available at
|
||||
`http://github.com/danlucraft/retwis-rb <http://github.com/danlucraft/retwis-rb>`_
|
||||
scanty-redis
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Scanty is *minimal* blogging software developed by Adam Wiggins
|
||||
(`@hirodusk <http://twitter.com/hirodusk>`_) It is not a blogging
|
||||
engine, but it�s small and easy to modify, so it could be the
|
||||
starting point for your blog.
|
||||
`This fork <http://github.com/adamwiggins/scanty-redis>`_ is
|
||||
modified to use Redis, a full featured key-value database, instead
|
||||
of SQL.
|
||||
Note Taking
|
||||
~~~~~~~~~~~
|
||||
|
||||
A *very simple* note taking example of Ruby and Redis application
|
||||
using `Sinatra <http://www.sinatrarb.com/>`_. Developed by Pieter
|
||||
Noordhuis `@pnoordhuis <http://twitter.com/pnoordhuis>`_, you can
|
||||
check the code at
|
||||
`http://gist.github.com/86714 <http://gist.github.com/86714>`_
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,298 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**ProtocolSpecification: Contents**
|
||||
`Networking layer <#Networking%20layer>`_
|
||||
`Requests <#Requests>`_
|
||||
`The new unified request protocol <#The%20new%20unified%20request%20protocol>`_
|
||||
`Replies <#Replies>`_
|
||||
`Single line reply <#Single%20line%20reply>`_
|
||||
`Error reply <#Error%20reply>`_
|
||||
`Integer reply <#Integer%20reply>`_
|
||||
`Bulk replies <#Bulk%20replies>`_
|
||||
`Multi-Bulk replies <#Multi-Bulk%20replies>`_
|
||||
`Nil elements in Multi-Bulk replies <#Nil%20elements%20in%20Multi-Bulk%20replies>`_
|
||||
`Multiple commands and pipelining <#Multiple%20commands%20and%20pipelining>`_
|
||||
`The old protocol for sending commands <#The%20old%20protocol%20for%20sending%20commands>`_
|
||||
`Inline Commands <#Inline%20Commands>`_
|
||||
`Bulk commands <#Bulk%20commands>`_
|
||||
ProtocolSpecification
|
||||
=====================
|
||||
|
||||
= Protocol Specification =
|
||||
The Redis protocol is a compromise between the following things:
|
||||
|
||||
- Simple to implement.
|
||||
- Fast to parse by a computer.
|
||||
- Easy enough to parse by a human.
|
||||
|
||||
Networking layer
|
||||
----------------
|
||||
|
||||
A client connects to a Redis server creating a TCP connection to
|
||||
the port 6379. Every Redis command or data transmitted by the
|
||||
client and the server is terminated by "\\r\\n" (CRLF).
|
||||
Requests
|
||||
========
|
||||
|
||||
Redis accepts commands composed of different arguments. Once a
|
||||
command is received, it is processed and a reply is sent back to
|
||||
the client.
|
||||
The new unified request protocol
|
||||
--------------------------------
|
||||
|
||||
The new unified protocol was introduced in Redis 1.2, but it became
|
||||
the standard way for talking with the Redis server in Redis 2.0.
|
||||
In the unified protocol all the arguments sent to the Redis server
|
||||
are binary safe. This is the general form:
|
||||
::
|
||||
|
||||
*<number of arguments> CR LF
|
||||
$<number of bytes of argument 1> CR LF
|
||||
<argument data> CR LF
|
||||
...
|
||||
$<number of bytes of argument N> CR LF
|
||||
<argument data> CR LF
|
||||
|
||||
See the following example:
|
||||
::
|
||||
|
||||
*3
|
||||
$3
|
||||
SET
|
||||
$5
|
||||
mykey
|
||||
$7
|
||||
myvalue
|
||||
|
||||
This is how the above command looks as a quoted string, so that it
|
||||
is possible to see the exact value of every byte in the query:
|
||||
::
|
||||
|
||||
"*3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$8\r\nmyvalue\r\n"
|
||||
|
||||
As you will see in a moment this format is also used in Redis
|
||||
replies. The format used for every argument "$6\\r\\nmydata\\r\\n"
|
||||
is called a Bulk Reply. While the actual unified request protocol
|
||||
is what Redis uses to return list of items, and is called a Multi
|
||||
Bulk Reply. It is just the sum of N different Bulk Replies prefixed
|
||||
by a ``*<argc>\r\n`` string where ``<argc>`` is the number of
|
||||
arguments (Bulk Replies) that will follow.
|
||||
Replies
|
||||
=======
|
||||
|
||||
Redis will reply to commands with different kinds of replies. It is
|
||||
possible to check the kind of reply from the first byte sent by the
|
||||
server:
|
||||
|
||||
- With a single line reply the first byte of the reply will be "+"
|
||||
- With an error message the first byte of the reply will be "-"
|
||||
- With an integer number the first byte of the reply will be ":"
|
||||
- With bulk reply the first byte of the reply will be "$"
|
||||
- With multi-bulk reply the first byte of the reply will be
|
||||
"``*``"
|
||||
|
||||
Single line reply
|
||||
-----------------
|
||||
|
||||
A single line reply is in the form of a single line string starting
|
||||
with "+" terminated by "\\r\\n". For example:
|
||||
::
|
||||
|
||||
+OK
|
||||
|
||||
The client library should return everything after the "+", that is,
|
||||
the string "OK" in the example.
|
||||
The following commands reply with a single line reply: PING, SET,
|
||||
SELECT, SAVE, BGSAVE, SHUTDOWN, RENAME, LPUSH, RPUSH, LSET, LTRIM
|
||||
Error reply
|
||||
-----------
|
||||
|
||||
Errors are sent exactly like Single Line Replies. The only
|
||||
difference is that the first byte is "-" instead of "+".
|
||||
Error replies are only sent when something strange happened, for
|
||||
instance if you try to perform an operation against the wrong data
|
||||
type, or if the command does not exist and so forth. So an
|
||||
exception should be raised by the library client when an Error
|
||||
Reply is received.
|
||||
Integer reply
|
||||
-------------
|
||||
|
||||
This type of reply is just a CRLF terminated string representing an
|
||||
integer, prefixed by a ":" byte. For example ":0\\r\\n", or
|
||||
":1000\\r\\n" are integer replies.
|
||||
With commands like INCR or LASTSAVE using the integer reply to
|
||||
actually return a value there is no special meaning for the
|
||||
returned integer. It is just an incremental number for INCR, a UNIX
|
||||
time for LASTSAVE and so on.
|
||||
Some commands like EXISTS will return 1 for true and 0 for false.
|
||||
Other commands like SADD, SREM and SETNX will return 1 if the
|
||||
operation was actually done, 0 otherwise.
|
||||
The following commands will reply with an integer reply: SETNX,
|
||||
DEL, EXISTS, INCR, INCRBY, DECR, DECRBY, DBSIZE, LASTSAVE,
|
||||
RENAMENX, MOVE, LLEN, SADD, SREM, SISMEMBER, SCARD
|
||||
Bulk replies
|
||||
------------
|
||||
|
||||
Bulk replies are used by the server in order to return a single
|
||||
binary safe string.
|
||||
::
|
||||
|
||||
C: GET mykey
|
||||
S: $6
|
||||
S: foobar
|
||||
|
||||
The server sends as the first line a "$" byte followed by the
|
||||
number of bytes of the actual reply, followed by CRLF, then the
|
||||
actual data bytes are sent, followed by additional two bytes for
|
||||
the final CRLF. The exact sequence sent by the server is:
|
||||
::
|
||||
|
||||
"$6\r\nfoobar\r\n"
|
||||
|
||||
If the requested value does not exist the bulk reply will use the
|
||||
special value -1 as data length, example:
|
||||
::
|
||||
|
||||
C: GET nonexistingkey
|
||||
S: $-1
|
||||
|
||||
The client library API should not return an empty string, but a nil
|
||||
object, when the requested object does not exist. For example a
|
||||
Ruby library should return 'nil' while a C library should return
|
||||
NULL (or set a special flag in the reply object), and so forth.
|
||||
Multi-Bulk replies
|
||||
------------------
|
||||
|
||||
Commands like LRANGE need to return multiple values (every element
|
||||
of the list is a value, and LRANGE needs to return more than a
|
||||
single element). This is accomplished using multiple bulk writes,
|
||||
prefixed by an initial line indicating how many bulk writes will
|
||||
follow. The first byte of a multi bulk reply is always ``*``.
|
||||
Example:
|
||||
::
|
||||
|
||||
C: LRANGE mylist 0 3
|
||||
S: *4
|
||||
S: $3
|
||||
S: foo
|
||||
S: $3
|
||||
S: bar
|
||||
S: $5
|
||||
S: Hello
|
||||
S: $5
|
||||
S: World
|
||||
|
||||
As you can see the multi bulk reply is exactly the same format used
|
||||
in order to send commands to the Redis server unsing the unified
|
||||
protocol.
|
||||
The first line the server sent is
|
||||
"**4\\r\\n" in order to specify that four bulk replies will follow. Then every bulk write is transmitted.If the specified key does not exist, instead of the number of elements in the list the special value -1 is sent as count. Example:**
|
||||
::
|
||||
|
||||
C: LRANGE nokey 0 1
|
||||
S: *-1
|
||||
|
||||
A client library API SHOULD return a nil object and not an empty
|
||||
list when this happens. This makes possible to distinguish between
|
||||
empty list and other error conditions (for instance a timeout
|
||||
condition in the BLPOP command).
|
||||
Nil elements in Multi-Bulk replies
|
||||
----------------------------------
|
||||
|
||||
Single elements of a multi bulk reply may have -1 length, in order
|
||||
to signal that this elements are missing and not empty strings.
|
||||
This can happen with the SORT command when used with the GET
|
||||
*pattern* option when the specified key is missing. Example of a
|
||||
multi bulk reply containing an empty element:
|
||||
::
|
||||
|
||||
S: *3
|
||||
S: $3
|
||||
S: foo
|
||||
S: $-1
|
||||
S: $3
|
||||
S: bar
|
||||
|
||||
The second element is nul. The client library should return
|
||||
something like this:
|
||||
::
|
||||
|
||||
["foo",nil,"bar"]
|
||||
|
||||
Multiple commands and pipelining
|
||||
--------------------------------
|
||||
|
||||
A client can use the same connection in order to issue multiple
|
||||
commands. Pipelining is supported so multiple commands can be sent
|
||||
with a single write operation by the client, it is not needed to
|
||||
read the server reply in order to issue the next command. All the
|
||||
replies can be read at the end.
|
||||
Usually Redis server and client will have a very fast link so this
|
||||
is not very important to support this feature in a client
|
||||
implementation, still if an application needs to issue a very large
|
||||
number of commands in short time to use pipelining can be much
|
||||
faster.
|
||||
The old protocol for sending commands
|
||||
=====================================
|
||||
|
||||
Before of the Unified Request Protocol Redis used a different
|
||||
protocol to send commands, that is still supported since it is
|
||||
simpler to type by hand via telnet. In this protocol there are two
|
||||
kind of commands:
|
||||
\* Inline commands: simple commands where argumnets are just space
|
||||
separated strings. No binary safeness is possible.\* Bulk commands:
|
||||
bulk commands are exactly like inline commands, but the last
|
||||
argument is handled in a special way in order to allow for a
|
||||
binary-safe last argument.
|
||||
|
||||
Inline Commands
|
||||
---------------
|
||||
|
||||
The simplest way to send Redis a command is via Inline Commands.
|
||||
The following is an example of a server/client chat using an inline
|
||||
command (the server chat starts with S:, the client chat with C:)
|
||||
::
|
||||
|
||||
C: PING
|
||||
S: +PONG
|
||||
|
||||
The following is another example of an INLINE command returning an
|
||||
integer:
|
||||
::
|
||||
|
||||
C: EXISTS somekey
|
||||
S: :0
|
||||
|
||||
Since 'somekey' does not exist the server returned ':0'.
|
||||
Note that the EXISTS command takes one argument. Arguments are
|
||||
separated by spaces.
|
||||
Bulk commands
|
||||
-------------
|
||||
|
||||
Some commands when sent as inline commands require a special form
|
||||
in order to support a binary safe last argument. This commands will
|
||||
use the last argument for a "byte count", then the bulk data is
|
||||
sent (that can be binary safe since the server knows how many bytes
|
||||
to read).
|
||||
See for instance the following example:
|
||||
::
|
||||
|
||||
C: SET mykey 6
|
||||
C: foobar
|
||||
S: +OK
|
||||
|
||||
The last argument of the commnad is '6'. This specify the number of
|
||||
DATA bytes that will follow, that is, the string "foobar". Note
|
||||
that even this bytes are terminated by two additional bytes of
|
||||
CRLF.
|
||||
All the bulk commands are in this exact form: instead of the last
|
||||
argument the number of bytes that will follow is specified,
|
||||
followed by the bytes composing the argument itself, and CRLF. In
|
||||
order to be more clear for the programmer this is the string sent
|
||||
by the client in the above sample:
|
||||
"SET mykey 6\\r\\nfoobar\\r\\n"
|
||||
|
||||
Redis has an internal list of what command is inline and what
|
||||
command is bulk, so you have to send this commands accordingly. It
|
||||
is strongly suggested to use the new Unified Request Protocol
|
||||
instead.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,240 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**PublishSubscribe: Contents**
|
||||
`UNSUBSCRIBE channel\_1 channel\_2 ... channel\_N <#UNSUBSCRIBE%20channel_1%20channel_2%20...%20channel_N>`_
|
||||
`UNSUBSCRIBE (unsubscribe from all channels) <#UNSUBSCRIBE%20(unsubscribe%20from%20all%20channels)>`_
|
||||
`PSUBSCRIBE pattern\_1 pattern\_2 ... pattern\_N <#PSUBSCRIBE%20pattern_1%20pattern_2%20...%20pattern_N>`_
|
||||
`PUNSUBSCRIBE pattern\_1 pattern\_2 ... pattern\_N <#PUNSUBSCRIBE%20pattern_1%20pattern_2%20...%20pattern_N>`_
|
||||
`PUNSUBSCRIBE (unsubscribe from all patterns) <#PUNSUBSCRIBE%20(unsubscribe%20from%20all%20patterns)>`_
|
||||
`PUBLISH channel message <#PUBLISH%20channel%20message>`_
|
||||
`Format of pushed messages <#Format%20of%20pushed%20messages>`_
|
||||
`Unsubscribing from all the channels at once <#Unsubscribing%20from%20all%20the%20channels%20at%20once>`_
|
||||
`Wire protocol example <#Wire%20protocol%20example>`_
|
||||
`PSUBSCRIBE and PUNSUBSCRIBE: pattern matching subscriptions <#PSUBSCRIBE%20and%20PUNSUBSCRIBE:%20pattern%20matching%20subscriptions>`_
|
||||
`Messages matching both a pattern and a channel subscription <#Messages%20matching%20both%20a%20pattern%20and%20a%20channel%20subscription>`_
|
||||
`The meaning of the count of subscriptions with pattern matching <#The%20meaning%20of%20the%20count%20of%20subscriptions%20with%20pattern%20matching>`_
|
||||
`More details on the PUBLISH command <#More%20details%20on%20the%20PUBLISH%20command>`_
|
||||
`Programming Example <#Programming%20Example>`_
|
||||
`Client library implementations hints <#Client%20library%20implementations%20hints>`_
|
||||
PublishSubscribe
|
||||
================
|
||||
|
||||
=SUBSCRIBE channel\_1 channel\_2 ... channel\_N=
|
||||
UNSUBSCRIBE channel\_1 channel\_2 ... channel\_N
|
||||
================================================
|
||||
|
||||
UNSUBSCRIBE (unsubscribe from all channels)
|
||||
===========================================
|
||||
|
||||
PSUBSCRIBE pattern\_1 pattern\_2 ... pattern\_N
|
||||
===============================================
|
||||
|
||||
PUNSUBSCRIBE pattern\_1 pattern\_2 ... pattern\_N
|
||||
=================================================
|
||||
|
||||
PUNSUBSCRIBE (unsubscribe from all patterns)
|
||||
============================================
|
||||
|
||||
PUBLISH channel message
|
||||
=======================
|
||||
|
||||
Time complexity: subscribe is O(1), unsubscribe is O(N) where N is
|
||||
the number of clients already subscribed to a channel, publish is
|
||||
O(N+M) where N is the number of clients subscribed to the receiving
|
||||
channel, and M is the total number of subscribed patterns (by any
|
||||
client). Psubscribe is O(N) where N is the number of patterns the
|
||||
Psubscribing client is already subscribed to. Punsubscribe is
|
||||
O(N+M) where N is the number of patterns the Punsubscribing client
|
||||
is already subscribed and M is the number of total patterns
|
||||
subscribed in the system (by any client).
|
||||
**Note**: this commands are available starting form Redis 2.0.0
|
||||
SUBSCRIBE, UNSUBSCRIBE and PUBLISH commands implement
|
||||
the`Publish/Subscribe messaging paradigm <http://en.wikipedia.org/wiki/Publish/subscribe>`_
|
||||
where (citing Wikipedia) senders (publishers) are not programmed to
|
||||
send their messages to specific receivers (subscribers). Rather,
|
||||
published messages are characterized into channels, without
|
||||
knowledge of what (if any) subscribers there may be. Subscribers
|
||||
express interest in one or more channels, and only receive messages
|
||||
that are of interest, without knowledge of what (if any) publishers
|
||||
there are. This decoupling of publishers and subscribers can allow
|
||||
for greater scalability and a more dynamic network topology.
|
||||
|
||||
For instance in order to subscribe to the channels foo and bar the
|
||||
clientwill issue the SUBSCRIBE command followed by the names of the
|
||||
channels.
|
||||
|
||||
::
|
||||
|
||||
SUBSCRIBE foo bar
|
||||
|
||||
All the messages sent by other clients to this channels will be
|
||||
pushed bythe Redis server to all the subscribed clients, in the
|
||||
form of a threeelements bulk reply, where the first element is the
|
||||
message type, thesecond the originating channel, and the third
|
||||
argument the message payload.
|
||||
|
||||
A client subscribed to 1 or more channels should NOT issue other
|
||||
commandsother than SUBSCRIBE and UNSUBSCRIBE, but can subscribe or
|
||||
unsubscribeto other channels dynamically.
|
||||
|
||||
The reply of the SUBSCRIBE and UNSUBSCRIBE operations are sent in
|
||||
the formof messages, so that the client can just read a coherent
|
||||
stream of messageswhere the first element indicates the kind of
|
||||
message.
|
||||
|
||||
Format of pushed messages
|
||||
-------------------------
|
||||
|
||||
Messages are in the form of multi bulk replies with three
|
||||
elements.The first element is the kind of message:
|
||||
|
||||
|
||||
- "subscribe": means that we successfully subscribed to the
|
||||
channel given as second element of the multi bulk reply. The third
|
||||
argument represents the number of channels we are currently
|
||||
subscribed to.
|
||||
- "unsubscribe": means that we successfully unsubscribed from the
|
||||
channel given as second element of the multi bulk reply. The third
|
||||
argument represents the number of channels we are currently
|
||||
subscribed to. If this latest argument is zero, we are no longer
|
||||
subscribed to any channel, and the client can issue any kind of
|
||||
Redis command as we are outside the Pub/sub state.
|
||||
- "message": it is a message received as result of a PUBLISH
|
||||
command issued by another client. The second element is the name of
|
||||
the originating channel, and the third the actual message payload.
|
||||
|
||||
Unsubscribing from all the channels at once
|
||||
-------------------------------------------
|
||||
|
||||
If the UNSUBSCRIBE command is issued without additional arguments,
|
||||
it is equivalent to unsubscribing to all the channels we are
|
||||
currently subscribed. A message for every unsubscribed channel will
|
||||
be received.
|
||||
Wire protocol example
|
||||
---------------------
|
||||
|
||||
::
|
||||
|
||||
SUBSCRIBE first second
|
||||
*3
|
||||
$9
|
||||
subscribe
|
||||
$5
|
||||
first
|
||||
:1
|
||||
*3
|
||||
$9
|
||||
subscribe
|
||||
$6
|
||||
second
|
||||
:2
|
||||
|
||||
at this point from another client we issue a PUBLISH operation
|
||||
against the channel named "second". This is what the first client
|
||||
receives:
|
||||
::
|
||||
|
||||
*3
|
||||
$7
|
||||
message
|
||||
$6
|
||||
second
|
||||
$5
|
||||
Hello
|
||||
|
||||
Now the client unsubscribes itself from all the channels using the
|
||||
UNSUBSCRIBE command without additional arguments:
|
||||
::
|
||||
|
||||
UNSUBSCRIBE
|
||||
*3
|
||||
$11
|
||||
unsubscribe
|
||||
$6
|
||||
second
|
||||
:1
|
||||
*3
|
||||
$11
|
||||
unsubscribe
|
||||
$5
|
||||
first
|
||||
:0
|
||||
|
||||
PSUBSCRIBE and PUNSUBSCRIBE: pattern matching subscriptions
|
||||
-----------------------------------------------------------
|
||||
|
||||
Redis Pub/Sub implementation supports pattern matching. Clients may
|
||||
subscribe to glob style patterns in order to receive all the
|
||||
messages sent to channel names matching a given pattern.
|
||||
For instance the command:
|
||||
::
|
||||
|
||||
PSUBSCRIBE news.*
|
||||
|
||||
Will receive all the messages sent to the channel
|
||||
news.art.figurative and news.music.jazz and so forth. All the glob
|
||||
style patterns as valid, so multiple wild cards are supported.
|
||||
Messages received as a result of pattern matching are sent in a
|
||||
different format:
|
||||
|
||||
- The type of the message is "pmessage": it is a message received
|
||||
as result of a PUBLISH command issued by another client, matching a
|
||||
pattern matching subscription. The second element is the original
|
||||
pattern matched, the third element is the name of the originating
|
||||
channel, and the last element the actual message payload.
|
||||
|
||||
Similarly to SUBSCRIBE and UNSUBSCRIBE, PSUBSCRIBE and PUNSUBSCRIBE
|
||||
commands are acknowledged by the system sending a message of type
|
||||
"psubscribe" and "punsubscribe" using the same format as the
|
||||
"subscribe" and "unsubscribe" message format.
|
||||
Messages matching both a pattern and a channel subscription
|
||||
-----------------------------------------------------------
|
||||
|
||||
A client may receive a single message multiple time if it's
|
||||
subscribed to multiple patterns matching a published message, or it
|
||||
is subscribed to both patterns and channels matching the message.
|
||||
Like in the following example:
|
||||
::
|
||||
|
||||
SUBSCRIBE foo
|
||||
PSUBSCRIBE f*
|
||||
|
||||
In the above example, if a message is sent to the **foo** channel,
|
||||
the client will receive two messages, one of type "message" and one
|
||||
of type "pmessage".
|
||||
The meaning of the count of subscriptions with pattern matching
|
||||
---------------------------------------------------------------
|
||||
|
||||
In **subscribe**, **unsubscribe**, **psubscribe** and
|
||||
**punsubscribe** message types, the last argument is the count of
|
||||
subscriptions still active. This number is actually the total
|
||||
number of channels and patterns the client is still subscribed to.
|
||||
So the client will exit the Pub/Sub state only when this count will
|
||||
drop to zero as a result of unsubscription from all the channels
|
||||
and patterns.
|
||||
More details on the PUBLISH command
|
||||
-----------------------------------
|
||||
|
||||
The Publish command is a bulk command where the first argument is
|
||||
the target class, and the second argument the data to send. It
|
||||
returns an Integer Reply representing the number of clients that
|
||||
received the message (that is, the number of clients that were
|
||||
listening for this class).
|
||||
Programming Example
|
||||
-------------------
|
||||
|
||||
Pieter Noordhuis provided a great example using Event-machine and
|
||||
Redis to create
|
||||
`a multi user high performance web chat <http://chat.redis-db.com>`_,
|
||||
with source code included of course!
|
||||
Client library implementations hints
|
||||
------------------------------------
|
||||
|
||||
Because all the messages received contain the original subscription
|
||||
causing the message delivery (the channel in the case of "message"
|
||||
type, and the original pattern in the case of "pmessage" type)
|
||||
clinet libraries may bind the original subscription to callbacks
|
||||
(that can be anonymous functions, blocks, function pointers, and so
|
||||
forth), using an hash table.
|
||||
When a message is received an O(1) lookup can be done in order to
|
||||
deliver the message to the registered callback.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,108 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**QuickStart: Contents**
|
||||
`Quick Start <#Quick%20Start>`_
|
||||
`Obtain the latest version <#Obtain%20the%20latest%20version>`_
|
||||
`Compile <#Compile>`_
|
||||
`Run the server <#Run%20the%20server>`_
|
||||
`Play with the built in client <#Play%20with%20the%20built%20in%20client>`_
|
||||
`Further reading <#Further%20reading>`_
|
||||
QuickStart
|
||||
==========
|
||||
|
||||
#sidebar `RedisGuides <RedisGuides.html>`_
|
||||
Quick Start
|
||||
===========
|
||||
|
||||
This quickstart is a five minutes howto on how to get started with
|
||||
Redis. For more information on Redis check
|
||||
`Redis Documentation Index <http://code.google.com/p/redis/wiki/index>`_.
|
||||
Obtain the latest version
|
||||
-------------------------
|
||||
|
||||
The latest stable source distribution of Redis can be obtained
|
||||
`at this location as a tarball <http://code.google.com/p/redis/downloads/list>`_.
|
||||
::
|
||||
|
||||
$ wget http://redis.googlecode.com/files/redis-1.02.tar.gz
|
||||
|
||||
The unstable source code, with more features but not ready for
|
||||
production, can be downloaded using git:
|
||||
::
|
||||
|
||||
$ git clone git://github.com/antirez/redis.git
|
||||
|
||||
Compile
|
||||
-------
|
||||
|
||||
Redis can be compiled in most
|
||||
`POSIX systems <SupportedPlatforms.html>`_. To compile Redis just
|
||||
untar the tar.gz, enter the directly and type 'make'.
|
||||
::
|
||||
|
||||
$ tar xvzf redis-1.02.tar.gz
|
||||
$ cd redis-1.02
|
||||
$ make
|
||||
|
||||
In order to test if the Redis server is working well in your
|
||||
computer make sure to run ``make test`` and check that all the
|
||||
tests are passed.
|
||||
Run the server
|
||||
--------------
|
||||
|
||||
Redis can run just fine without a configuration file (when executed
|
||||
without a config file a standard configuration is used). To run
|
||||
Redis just type the following command:
|
||||
::
|
||||
|
||||
$ ./redis-server
|
||||
|
||||
With the `default configuration <Configuration.html>`_ Redis will
|
||||
log to the standard output so you can check what happens. Later,
|
||||
you can `change the default settings <Configuration.html>`_.
|
||||
Play with the built in client
|
||||
-----------------------------
|
||||
|
||||
Redis ships with a command line client that is automatically
|
||||
compiled when you ran ``make`` and it is called ``redis-cli``For
|
||||
instance to set a key and read back the value use the following:
|
||||
::
|
||||
|
||||
$ ./redis-cli set mykey somevalue
|
||||
OK
|
||||
$ ./redis-cli get mykey
|
||||
somevalue
|
||||
|
||||
What about adding elements to a `list <Lists.html>`_:
|
||||
::
|
||||
|
||||
$ ./redis-cli lpush mylist firstvalue
|
||||
OK
|
||||
$ ./redis-cli lpush mylist secondvalue
|
||||
OK
|
||||
$ ./redis-cli lpush mylist thirdvalue
|
||||
OK
|
||||
$ ./redis-cli lrange mylist 0 -1
|
||||
1. thirdvalue
|
||||
2. secondvalue
|
||||
3. firstvalue
|
||||
$ ./redis-cli rpop mylist
|
||||
firstvalue
|
||||
$ ./redis-cli lrange mylist 0 -1
|
||||
1. thirdvalue
|
||||
2. secondvalue
|
||||
|
||||
Further reading
|
||||
---------------
|
||||
|
||||
|
||||
- What to play more with Redis? Read
|
||||
`Fifteen minutes introduction to Redis data types <IntroductionToRedisDataTypes.html>`_.
|
||||
- Check all the `Features <Features.html>`_
|
||||
- Read the full list of available commands in the
|
||||
`Command Reference <CommandReference.html>`_.
|
||||
- Start using Redis from your
|
||||
`favorite language <SupportedLanguages.html>`_.
|
||||
- Take a look at some
|
||||
`Programming Examples <ProgrammingExamples.html>`_.
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,20 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**QuitCommand: Contents**
|
||||
`Quit <#Quit>`_
|
||||
`Return value <#Return%20value>`_
|
||||
QuitCommand
|
||||
===========
|
||||
|
||||
#sidebar
|
||||
`ConnectionHandlingSidebar <ConnectionHandlingSidebar.html>`_
|
||||
Quit
|
||||
====
|
||||
|
||||
Ask the server to silently close the connection.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
None. The connection is closed as soon as the QUIT command is
|
||||
received.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,271 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**README: Contents**
|
||||
`All data in memory, but saved on disk <#All%20data%20in%20memory,%20but%20saved%20on%20disk>`_
|
||||
`Master-Slave replication made trivial <#Master-Slave%20replication%20made%20trivial>`_
|
||||
`It's persistent but supports expires <#It's%20persistent%20but%20supports%20expires>`_
|
||||
`Beyond key-value databases <#Beyond%20key-value%20databases>`_
|
||||
`Multiple databases support <#Multiple%20databases%20support>`_
|
||||
`Know more about Redis! <#Know%20more%20about%20Redis!>`_
|
||||
`Redis Tutorial <#Redis%20Tutorial>`_
|
||||
`License <#License>`_
|
||||
`Credits <#Credits>`_
|
||||
README
|
||||
======
|
||||
|
||||
= Introduction =
|
||||
Redis is an extremely fast and powerful key-value store database
|
||||
and server implemented in ANSI C. Redis offers many different ways
|
||||
to do one straightforward thing: store a value ("antirez") to a key
|
||||
("redis"). While the format of keys must always be simple strings,
|
||||
the power is with the values, which support the following data
|
||||
types:
|
||||
|
||||
- `Strings <Strings.html>`_
|
||||
- `Lists <Lists.html>`_
|
||||
- `Sets <Sets.html>`_
|
||||
- `Sorted Sets (zsets) <SortedSets.html>`_
|
||||
- `Hashes <Hashes.html>`_
|
||||
|
||||
Each value type has an associated list of commands which can
|
||||
operate on them, and the
|
||||
`The Redis Command Reference <CommandReference.html>`_ contains an
|
||||
up to date list of these commands, organized primarily by data
|
||||
type. The Redis source also includes a
|
||||
`Redis command line interface <RedisCLI.html>`_ which allows you to
|
||||
interact directly with the server, and is the means by which this
|
||||
introduction will provide examples. Once you walk through the
|
||||
`Redis Quick Start Guide <QuickStart.html>`_ to get your instance
|
||||
of Redis running, you can follow along.
|
||||
One of the most powerful aspects of Redis is the wide range of
|
||||
commands which are optimized to work with specific data value types
|
||||
and executed as atomic server-side operations. The
|
||||
`List <Lists.html>`_ type is a great example - Redis implements
|
||||
O(1) operations such as `LPUSH <RpushCommand.html>`_ or
|
||||
`RPUSH <RpushCommand.html>`_, which have accompanying
|
||||
`LPOP <LpopCommand.html>`_ and `RPOP <LpopCommand.html>`_ methods:
|
||||
::
|
||||
|
||||
redis> lpush programming_languages C
|
||||
OK
|
||||
redis> lpush programming_languages Ruby
|
||||
OK
|
||||
redis> rpush programming_languages Python
|
||||
OK
|
||||
redis> rpop programming_languages
|
||||
Python
|
||||
redis> lpop programming_languages
|
||||
Ruby
|
||||
|
||||
More complex operations are available for each data type as well.
|
||||
Continuing with lists, you can get a range of elements with
|
||||
`LRANGE <LrangeCommand.html>`_ (O(start+n)) or trim the list with
|
||||
`LTRIM <LtrimCommand.html>`_ (O(n)):
|
||||
::
|
||||
|
||||
redis> lpush cities NYC
|
||||
OK
|
||||
redis> lpush cities SF
|
||||
OK
|
||||
redis> lpush cities Tokyo
|
||||
OK
|
||||
redis> lpush cities London
|
||||
OK
|
||||
redis> lpush cities Paris
|
||||
OK
|
||||
redis> lrange cities 0 2
|
||||
1. Paris
|
||||
2. London
|
||||
3. Tokyo
|
||||
redis> ltrim cities 0 1
|
||||
OK
|
||||
redis> lpop cities
|
||||
Paris
|
||||
redis> lpop cities
|
||||
London
|
||||
redis> lpop cities
|
||||
(nil)
|
||||
|
||||
You can also add and remove elements from a set, and perform
|
||||
intersections, unions, and differences.
|
||||
Redis can also be looked at as a data structures server. A Redis
|
||||
user is virtually provided with an interface to
|
||||
`Abstract Data Types <http://en.wikipedia.org/wiki/Abstract_data_type>`_,
|
||||
saving them from the responsibility of implementing concrete data
|
||||
structures and algorithms -- indeed both algorithms and data
|
||||
structures in Redis are properly chosen in order to obtain the best
|
||||
performance.
|
||||
All data in memory, but saved on disk
|
||||
=====================================
|
||||
|
||||
Redis loads and mantains the whole dataset into memory, but the
|
||||
dataset is persistent, since at the same time it is saved on disk,
|
||||
so that when the server is restarted data can be loaded back in
|
||||
memory.
|
||||
There are two kinds of persistence supported: the first one is
|
||||
called snapshotting. In this mode Redis periodically writes to disk
|
||||
asynchronously. The dataset is loaded from the dump every time the
|
||||
server is (re)started.
|
||||
Redis can be configured to save the dataset when a certain number
|
||||
of changes is reached and after a given number of seconds elapses.
|
||||
For example, you can configure Redis to save after 1000 changes and
|
||||
at most 60 seconds since the last save. You can specify any
|
||||
combination for these numbers.
|
||||
Because data is written asynchronously, when a system crash occurs,
|
||||
the last few queries can get lost (that is acceptable in many
|
||||
applications but not in all). In order to make this a non issue
|
||||
Redis supports another, safer persistence mode, called
|
||||
`Append Only File <AppendOnlyFileHowto.html>`_, where every command
|
||||
received altering the dataset (so not a read-only command, but a
|
||||
write command) is written on an append only file ASAP. This
|
||||
commands are *replayed* when the server is restarted in order to
|
||||
rebuild the dataset in memory.
|
||||
Redis Append Only File supports a very handy feature: the server is
|
||||
able to safely rebuild the append only file in background in a
|
||||
non-blocking fashion when it gets too long. You can find
|
||||
`more details in the Append Only File HOWTO <AppendOnlyFileHowto.html>`_.
|
||||
Master-Slave replication made trivial
|
||||
=====================================
|
||||
|
||||
Whatever will be the persistence mode you'll use Redis supports
|
||||
master-slave replications if you want to stay really safe or if you
|
||||
need to scale to huge amounts of reads.
|
||||
**Redis Replication is trivial to setup**. So trivial that all you
|
||||
need to do in order to configure a Redis server to be a slave of
|
||||
another one, with automatic synchronization if the link will go
|
||||
down and so forth, is the following config line:
|
||||
``slaveof 192.168.1.100 6379``.
|
||||
`We provide a Replication Howto <ReplicationHowto.html>`_ if you
|
||||
want to know more about this feature.
|
||||
It's persistent but supports expires
|
||||
====================================
|
||||
|
||||
Redis can be used as a **memcached on steroids** because is as fast
|
||||
as memcached but with a number of features more. Like memcached,
|
||||
Redis also supports setting timeouts to keys so that this key will
|
||||
be automatically removed when a given amount of time passes.
|
||||
Beyond key-value databases
|
||||
==========================
|
||||
|
||||
All these features allow to use Redis as the sole DB for your
|
||||
scalable application without the need of any relational database.
|
||||
`We wrote a simple Twitter clone in PHP + Redis <TwitterAlikeExample.html>`_
|
||||
to show a real world example, the link points to an article
|
||||
explaining the design and internals in very simple words.
|
||||
Multiple databases support
|
||||
==========================
|
||||
|
||||
Redis supports multiple databases with commands to atomically move
|
||||
keys from one database to the other. By default DB 0 is selected
|
||||
for every new connection, but using the SELECT command it is
|
||||
possible to select a different database. The MOVE operation can
|
||||
move an item from one DB to another atomically. This can be used as
|
||||
a base for locking free algorithms together with the 'RANDOMKEY'
|
||||
commands.
|
||||
Know more about Redis!
|
||||
======================
|
||||
|
||||
To really get a feeling about what Redis is and how it works please
|
||||
try reading
|
||||
`A fifteen minutes introduction to Redis data types <IntroductionToRedisDataTypes.html>`_.
|
||||
To know a bit more about how Redis works *internally* continue
|
||||
reading.
|
||||
Redis Tutorial
|
||||
==============
|
||||
|
||||
(note, you can skip this section if you are only interested in
|
||||
"formal" doc.)
|
||||
Later in this document you can find detailed information about
|
||||
Redis commands, the protocol specification, and so on. This kind of
|
||||
documentation is useful but... if you are new to Redis it is also
|
||||
BORING! The Redis protocol is designed so that is both pretty
|
||||
efficient to be parsed by computers, but simple enough to be used
|
||||
by humans just poking around with the 'telnet' command, so this
|
||||
section will show to the reader how to play a bit with Redis to get
|
||||
an initial feeling about it, and how it works.
|
||||
To start just compile redis with 'make' and start it with
|
||||
'./redis-server'. The server will start and log stuff on the
|
||||
standard output, if you want it to log more edit redis.conf, set
|
||||
the loglevel to debug, and restart it.
|
||||
You can specify a configuration file as unique parameter:
|
||||
./redis-server /etc/redis.conf
|
||||
|
||||
This is NOT required. The server will start even without a
|
||||
configuration file using a default built-in configuration.
|
||||
Now let's try to set a key to a given value:
|
||||
::
|
||||
|
||||
$ telnet localhost 6379
|
||||
Trying 127.0.0.1...
|
||||
Connected to localhost.
|
||||
Escape character is '^]'.
|
||||
SET foo 3
|
||||
bar
|
||||
+OK
|
||||
|
||||
The first line we sent to the server is "set foo 3". This means
|
||||
"set the key foo with the following three bytes I'll send you". The
|
||||
following line is the "bar" string, that is, the three bytes. So
|
||||
the effect is to set the key "foo" to the value "bar". Very simple!
|
||||
(note that you can send commands in lowercase and it will work
|
||||
anyway, commands are not case sensitive)
|
||||
Note that after the first and the second line we sent to the server
|
||||
there is a newline at the end. The server expects commands
|
||||
terminated by "\\r\\n" and sequence of bytes terminated by
|
||||
"\\r\\n". This is a minimal overhead from the point of view of both
|
||||
the server and client but allows us to play with Redis with the
|
||||
telnet command easily.
|
||||
The last line of the chat between server and client is "+OK". This
|
||||
means our key was added without problems. Actually SET can never
|
||||
fail but the "+OK" sent lets us know that the server received
|
||||
everything and the command was actually executed.
|
||||
Let's try to get the key content now:
|
||||
::
|
||||
|
||||
GET foo
|
||||
$3
|
||||
bar
|
||||
|
||||
Ok that's very similar to 'set', just the other way around. We sent
|
||||
"get foo", the server replied with a first line that is just the $
|
||||
character follwed by the number of bytes the value stored at key
|
||||
contained, followed by the actual bytes. Again "\\r\\n" are
|
||||
appended both to the bytes count and the actual data. In Redis
|
||||
slang this is called a bulk reply.
|
||||
What about requesting a non existing key?
|
||||
::
|
||||
|
||||
GET blabla
|
||||
$-1
|
||||
|
||||
When the key does not exist instead of the length, just the "$-1"
|
||||
string is sent. Since a -1 length of a bulk reply has no meaning it
|
||||
is used in order to specifiy a 'nil' value and distinguish it from
|
||||
a zero length value. Another way to check if a given key exists or
|
||||
not is indeed the EXISTS command:
|
||||
::
|
||||
|
||||
EXISTS nokey
|
||||
:0
|
||||
EXISTS foo
|
||||
:1
|
||||
|
||||
As you can see the server replied ':0' the first time since 'nokey'
|
||||
does not exist, and ':1' for 'foo', a key that actually exists.
|
||||
Replies starting with the colon character are integer reply.
|
||||
Ok... now you know the basics, read the
|
||||
`REDIS COMMAND REFERENCE <CommandReference.html>`_ section to learn
|
||||
all the commands supported by Redis and the
|
||||
`PROTOCOL SPECIFICATION <ProtocolSpecification.html>`_ section for
|
||||
more details about the protocol used if you plan to implement one
|
||||
for a language missing a decent client implementation.
|
||||
License
|
||||
=======
|
||||
|
||||
Redis is released under the BSD license. See the COPYING file for
|
||||
more information.
|
||||
Credits
|
||||
=======
|
||||
|
||||
Redis is written and maintained by Salvatore Sanfilippo, Aka
|
||||
'antirez'.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,20 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**RandomkeyCommand: Contents**
|
||||
`RANDOMKEY <#RANDOMKEY>`_
|
||||
`Return value <#Return%20value>`_
|
||||
RandomkeyCommand
|
||||
================
|
||||
|
||||
#sidebar `GenericCommandsSidebar <GenericCommandsSidebar.html>`_
|
||||
RANDOMKEY
|
||||
=========
|
||||
|
||||
*Time complexity: O(1)*
|
||||
Return a randomly selected key from the currently selected DB.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Singe line reply <ReplyTypes.html>`_, specifically the randomly
|
||||
selected key or an empty string is the database is empty.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,42 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**Redis0100ChangeLog: Contents**
|
||||
`Redis 0.100 Changelog <#Redis%200.100%20Changelog>`_
|
||||
Redis0100ChangeLog
|
||||
==================
|
||||
|
||||
Redis 0.100 Changelog
|
||||
=====================
|
||||
|
||||
::
|
||||
|
||||
- SUNION, SDIFF, SUNIONSTORE, SDIFFSTORE commands implemented. (Aman Gupta, antirez)
|
||||
- Non blocking replication. Now while N slaves are synchronizing, the master will continue to ask to client queries. (antirez)
|
||||
- PHP client ported to PHP5 (antirez)
|
||||
- FLUSHALL/FLUSHDB no longer sync on disk. Just increment the dirty counter by the number of elements removed, that will probably trigger a background saving operation (antirez)
|
||||
- INCRBY/DECRBY now support 64bit increments, with tests (antirez)
|
||||
- New fields in INFO command, bgsave_in_progress and replication related (antirez)
|
||||
- Ability to specify a different file name for the DB (... can't remember ...)
|
||||
- GETSET command, atomic GET + SET (antirez)
|
||||
- SMOVE command implemented, atomic move-element across sets operation (antirez)
|
||||
- Ability to work with huge data sets, tested up to 350 million keys (antirez)
|
||||
- Warns if /proc/sys/vm/overcommit_memory is set to 0 on Linux. Also make sure to don't resize the hash tables while the child process is saving in order to avoid copy-on-write of memory pages (antirez)
|
||||
- Infinite number of arguments for MGET and all the other commands (antirez)
|
||||
- CPP client (Brian Hammond)
|
||||
- DEL is now a vararg, IMPORTANT: memory leak fixed in loading DB code (antirez)
|
||||
- Benchmark utility now supports random keys (antirez)
|
||||
- Timestamp in log lines (antirez)
|
||||
- Fix SINTER/UNIONSTORE to allow for &=/|= style operations (i.e. SINTERSTORE set1 set1 set2) (Aman Gupta)
|
||||
- Partial qsort implemented in SORT command, only when both BY and LIMIT is used (antirez)
|
||||
- Allow timeout=0 config to disable client timeouts (Aman Gupta)
|
||||
- Alternative (faster/simpler) ruby client API compatible with Redis-rb (antirez)
|
||||
- S*STORE now return the cardinality of the resulting set (antirez)
|
||||
- TTL command implemented (antirez)
|
||||
- Critical bug about glueoutputbuffers=yes fixed. Under load and with pipelining and clients disconnecting on the middle of the chat with the server, Redis could block. (antirez)
|
||||
- Different replication fixes (antirez)
|
||||
- SLAVEOF command implemented for remote replication management (antirez)
|
||||
- Issue with redis-client used in scripts solved, now to check if the latest argument must come from standard input we do not check that stdin is or not a tty but the command arity (antirez)
|
||||
- Warns if using the default config (antirez)
|
||||
- maxclients implemented, see redis.conf for details (antirez)
|
||||
- max bytes of a received command enlarged from 1k to 32k (antirez)
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,32 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**Redis0900ChangeLog: Contents**
|
||||
`CHANGELOG for Redis 0.900 <#CHANGELOG%20for%20Redis%200.900>`_
|
||||
Redis0900ChangeLog
|
||||
==================
|
||||
|
||||
CHANGELOG for Redis 0.900
|
||||
=========================
|
||||
|
||||
::
|
||||
|
||||
2009-06-16 client libraries updated (antirez)
|
||||
2009-06-16 Better handling of background saving process killed or crashed (antirez)
|
||||
2009-06-14 number of keys info in INFO command (Diego Rosario Brogna)
|
||||
2009-06-14 SPOP documented (antirez)
|
||||
2009-06-14 Clojure library (Ragnar Dahlén)
|
||||
2009-06-10 It is now possible to specify - as config file name to read it from stdin (antirez)
|
||||
2009-06-10 max bytes in an inline command raised to 1024*1024 bytes, in order to allow for very large MGETs and still protect from client crashes (antirez)
|
||||
2009-06-08 SPOP implemented. Hash table resizing for Sets and Expires too. Changed the resize policy to play better with RANDOMKEY and SPOP. (antirez)
|
||||
2009-06-07 some minor changes to the backtrace code (antirez)
|
||||
2009-06-07 enable backtrace capabilities only for Linux and MacOSX (antirez)
|
||||
2009-06-07 Dump a backtrace on sigsegv/sigbus, original coded (Diego Rosario Brogna)
|
||||
2009-06-05 Avoid a busy loop while sending very large replies against very fast links, this allows to be more responsive with other clients even under a KEY * against the loopback interface (antirez)
|
||||
2009-06-05 Kill the background saving process before performing SHUTDOWN to avoid races (antirez)
|
||||
2009-06-05 LREM now returns :0 for non existing keys (antirez)
|
||||
2009-06-05 added config.h for #ifdef business isolation, added fstat64 for Mac OS X (antirez)
|
||||
2009-06-04 macosx specific zmalloc.c, uses malloc_size function in order to avoid to waste memory and time to put an additional header (antirez)
|
||||
2009-06-04 DEBUG OBJECT implemented (antirez)
|
||||
2009-06-03 shareobjectspoolsize implemented in reds.conf, in order to control the pool size when object sharing is on (antirez)
|
||||
2009-05-27 maxmemory implemented (antirez)
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,51 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**RedisBigData: Contents**
|
||||
`BGSAVE and BGREWRITEAOF blocking fork() call <#BGSAVE%20and%20BGREWRITEAOF%20blocking%20fork()%20call>`_
|
||||
`Using multiple cores <#Using%20multiple%20cores>`_
|
||||
`Splitting data into multiple instances <#Splitting%20data%20into%20multiple%20instances>`_
|
||||
`BGSAVE / AOFSAVE memory usage, and copy on write <#BGSAVE%20/%20AOFSAVE%20memory%20usage,%20and%20copy%20on%20write>`_
|
||||
`BGSAVE / AOFSAVE time for big datasets <#BGSAVE%20/%20AOFSAVE%20time%20for%20big%20datasets>`_
|
||||
`Non blocking hash table <#Non%20blocking%20hash%20table>`_
|
||||
RedisBigData
|
||||
============
|
||||
|
||||
=Redis Big Data: facts and guidelines=
|
||||
BGSAVE and BGREWRITEAOF blocking fork() call
|
||||
--------------------------------------------
|
||||
|
||||
::
|
||||
|
||||
fork.c && ./a.out
|
||||
allocated: 1 MB, fork() took 0.000
|
||||
allocated: 10 MB, fork() took 0.001
|
||||
allocated: 100 MB, fork() took 0.007
|
||||
allocated: 1000 MB, fork() took 0.059
|
||||
allocated: 10000 MB, fork() took 0.460
|
||||
allocated: 20000 MB, fork() took 0.895
|
||||
allocated: 30000 MB, fork() took 1.327
|
||||
allocated: 40000 MB, fork() took 1.759
|
||||
allocated: 50000 MB, fork() took 2.190
|
||||
allocated: 60000 MB, fork() took 2.621
|
||||
allocated: 70000 MB, fork() took 3.051
|
||||
allocated: 80000 MB, fork() took 3.483
|
||||
allocated: 90000 MB, fork() took 3.911
|
||||
allocated: 100000 MB, fork() took 4.340
|
||||
allocated: 110000 MB, fork() took 4.770
|
||||
allocated: 120000 MB, fork() took 5.202
|
||||
|
||||
Using multiple cores
|
||||
--------------------
|
||||
|
||||
Splitting data into multiple instances
|
||||
--------------------------------------
|
||||
|
||||
BGSAVE / AOFSAVE memory usage, and copy on write
|
||||
------------------------------------------------
|
||||
|
||||
BGSAVE / AOFSAVE time for big datasets
|
||||
--------------------------------------
|
||||
|
||||
Non blocking hash table
|
||||
-----------------------
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,11 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**RedisCLI: Contents**
|
||||
`Redis CLI <#Redis%20CLI>`_
|
||||
RedisCLI
|
||||
========
|
||||
|
||||
Redis Command Line Interface
|
||||
Redis CLI
|
||||
=========
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,181 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**RedisEventLibrary: Contents**
|
||||
`Redis Event Library <#Redis%20Event%20Library>`_
|
||||
`Event Loop Initialization <#Event%20Loop%20Initialization>`_
|
||||
`aeCreateEventLoop <#aeCreateEventLoop>`_
|
||||
`aeCreateTimeEvent <#aeCreateTimeEvent>`_
|
||||
`aeCreateFileEvent <#aeCreateFileEvent>`_
|
||||
`Event Loop Processing <#Event%20Loop%20Processing>`_
|
||||
`aeProcessEvents <#aeProcessEvents>`_
|
||||
`processTimeEvents <#processTimeEvents>`_
|
||||
RedisEventLibrary
|
||||
=================
|
||||
|
||||
#sidebar `RedisInternals <RedisInternals.html>`_
|
||||
Redis Event Library
|
||||
===================
|
||||
|
||||
Redis implements its own event library. The event library is
|
||||
implemented in **ae.c**.
|
||||
The best way to understand how the Redis event library works is to
|
||||
understand how Redis uses it.
|
||||
Event Loop Initialization
|
||||
-------------------------
|
||||
|
||||
``initServer`` function defined in **redis.c** initializes the
|
||||
numerous fields of the ``redisServer`` structure variable. One such
|
||||
field is the Redis event loop ``el``:
|
||||
::
|
||||
|
||||
|
||||
aeEventLoop *el
|
||||
|
||||
``initServer`` initializes ``server.el`` field by calling
|
||||
``aeCreateEventLoop`` defined in **ae.c**. The definition of
|
||||
``aeEventLoop`` is below:
|
||||
::
|
||||
|
||||
typedef struct aeEventLoop
|
||||
{
|
||||
int maxfd;
|
||||
long long timeEventNextId;
|
||||
aeFileEvent events[AE_SETSIZE]; /* Registered events */
|
||||
aeFiredEvent fired[AE_SETSIZE]; /* Fired events */
|
||||
aeTimeEvent *timeEventHead;
|
||||
int stop;
|
||||
void *apidata; /* This is used for polling API specific data */
|
||||
aeBeforeSleepProc *beforesleep;
|
||||
} aeEventLoop;
|
||||
|
||||
aeCreateEventLoop
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
``aeCreateEventLoop`` first mallocs aeEventLoop structure then
|
||||
calls
|
||||
ae\_epoll.c:aeApiCreate``.``aeApiCreate``mallocs``aeApiState``that has two fields -``epfd``that holds the epoll file descriptor returned by a call from [http://man.cx/epoll_create%282%29 epoll_create] and``events``that is of type``struct
|
||||
epoll\_event``define by the Linux epoll library. The use of the``events``field will be described later. Next is 'ae.c:aeCreateTimeEvent``.
|
||||
But before that ``initServer`` call ``anet.c:anetTcpServer`` that
|
||||
creates and returns a *listening descriptor*. The descriptor is
|
||||
listens to **port 6379** by default. The returned
|
||||
*listening descriptor* is stored in ``server.fd`` field.
|
||||
aeCreateTimeEvent
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
``aeCreateTimeEvent`` accepts the following as parameters:
|
||||
|
||||
- eventLoop: This is ``server.el`` in **redis.c**
|
||||
- milliseconds: The number of milliseconds from the curent time
|
||||
after which the timer expires.
|
||||
- proc: Function pointer. Stores the address of the function that
|
||||
has to be called after the timer expires.
|
||||
- clientData: Mostly NULL.
|
||||
- finalizerProc: Pointer to the function that has to be called
|
||||
before the timed event is removed from the list of timed events.
|
||||
|
||||
``initServer`` calls ``aeCreateTimeEvent`` to add a timed event to
|
||||
``timeEventHead`` field of ``server.el``. ``timeEventHead`` is a
|
||||
pointer to a list of such timed events. The call to
|
||||
``aeCreateTimeEvent`` from ``redis.c:initServer`` function is given
|
||||
below:
|
||||
::
|
||||
|
||||
aeCreateTimeEvent(server.el /*eventLoop*/, 1 /*milliseconds*/, serverCron /*proc*/, NULL /*clientData*/, NULL /*finalizerProc*/);
|
||||
|
||||
``redis.c:serverCron`` performs many operations that helps keep
|
||||
Redis running properly.
|
||||
aeCreateFileEvent
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
The essence of ``aeCreateFileEvent`` function is to execute
|
||||
`epoll\_ctl <http://man.cx/epoll_ctl>`_ system call which adds a
|
||||
watch for ``EPOLLIN`` event on the *listening descriptor* create by
|
||||
``anetTcpServer`` and associate it with the epoll descriptor
|
||||
created by a call to ``aeCreateEventLoop``.
|
||||
Following is an explanation of what precisely ``aeCreateFileEvent``
|
||||
does when called from ``redis.c:initServer``.
|
||||
``initServer`` passes the following arguments to
|
||||
``aeCreateFileEvent``:
|
||||
|
||||
- server.el: The event loop created by ``aeCreateEventLoop``. The
|
||||
epoll descriptor is got from server.el.
|
||||
- server.fd: The *listening descriptor* that also serves as an
|
||||
index to access the relevant file event structure from the
|
||||
``eventLoop->events`` table and store extra information like the
|
||||
callback function.
|
||||
- AE\_READABLE: Signifies that server.fd has to be watched for
|
||||
EPOLLIN event.
|
||||
- acceptHandler: The function that has to be executed when the
|
||||
event being watched for is ready. This function pointer is stored
|
||||
in ``eventLoop->events[server.fd]->rfileProc``.
|
||||
|
||||
This completes the initialization of Redis event loop.
|
||||
Event Loop Processing
|
||||
---------------------
|
||||
|
||||
``ae.c:aeMain`` called from ``redis.c:main`` does the job of
|
||||
processing the event loop that is initialized in the previous
|
||||
phase.
|
||||
``ae.c:aeMain`` calls ``ae.c:aeProcessEvents`` in a while loop that
|
||||
processes pending time and file events.
|
||||
aeProcessEvents
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
``ae.c:aeProcessEvents`` looks for the time event that will be
|
||||
pending in the smallest amount of time by calling
|
||||
``ae.c:aeSearchNearestTimer`` on the event loop. In our case there
|
||||
is only one timer event in the event loop that was created by
|
||||
``ae.c:aeCreateTimeEvent``.
|
||||
Remember, that timer event created by ``aeCreateTimeEvent`` has by
|
||||
now probably elapsed because it had a expiry time of one
|
||||
millisecond. Since, the timer has already expired the seconds and
|
||||
microseconds fields of the ``tvp`` timeval structure variable is
|
||||
initialized to zero.
|
||||
The ``tvp`` structure variable along with the event loop variable
|
||||
is passed to ``ae_epoll.c:aeApiPoll``.
|
||||
``aeApiPoll`` functions does a
|
||||
`epoll\_wait <http://man.cx/epoll_wait>`_ on the epoll descriptor
|
||||
and populates the ``eventLoop->fired`` table with the details:
|
||||
|
||||
- fd: The descriptor that is now ready to do a read/write
|
||||
operation depending on the mask value. The
|
||||
- mask: The read/write event that can now be performed on the
|
||||
corresponding descriptor.
|
||||
|
||||
``aeApiPoll`` returns the number of such file events ready for
|
||||
operation. Now to put things in context, if any client has
|
||||
requested for a connection then aeApiPoll would have noticed it and
|
||||
populated the ``eventLoop->fired`` table with an entry of the
|
||||
descriptor being the *listening descriptor* and mask being
|
||||
``AE_READABLE``.
|
||||
Now, ``aeProcessEvents`` calls the ``redis.c:acceptHandler``
|
||||
registered as the callback. ``acceptHandler`` executes
|
||||
[`http://man.cx/accept(2 <http://man.cx/accept(2>`_) accept] on the
|
||||
*listening descriptor* returning a *connected descriptor* with the
|
||||
client. ``redis.c:createClient`` adds a file event on the
|
||||
*connected descriptor* through a call to ``ae.c:aeCreateFileEvent``
|
||||
like below:
|
||||
::
|
||||
|
||||
if (aeCreateFileEvent(server.el, c->fd, AE_READABLE,
|
||||
readQueryFromClient, c) == AE_ERR) {
|
||||
freeClient(c);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
``c`` is the ``redisClient`` structure variable and ``c->fd`` is
|
||||
the connected descriptor.
|
||||
Next the ``ae.c:aeProcessEvent`` calls ``ae.c:processTimeEvents``
|
||||
processTimeEvents
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
``ae.processTimeEvents`` iterates over list of time events starting
|
||||
at ``eventLoop->timeEventHead``.
|
||||
For every timed event that has elapsed ``processTimeEvents`` calls
|
||||
the registered callback. In this case it calls the only timed event
|
||||
callback registered, that is, ``redis.c:serverCron``. The callback
|
||||
returns the time in milliseconds after which the callback must be
|
||||
called again. This change is recorded via a call to
|
||||
``ae.c:aeAddMilliSeconds`` and will be handled on the next
|
||||
iteration of ``ae.c:aeMain`` while loop.
|
||||
That's all.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,14 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**RedisGuides: Contents**
|
||||
RedisGuides
|
||||
===========
|
||||
|
||||
= Redis Guides and Howtos=
|
||||
|
||||
- `Redis Quick Start <QuickStart.html>`_
|
||||
- `Virutal Memory User Guide <VirtualMemoryUserGuide.html>`_
|
||||
- `A Fifteen Minutes Introduction to the Redis Data Types <IntroductionToRedisDataTypes.html>`_
|
||||
- `The Redis Replication HOWTO <ReplicationHowto.html>`_
|
||||
- `The Append Only File HOWTO <AppendOnlyFileHowto.html>`_
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,38 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**RedisInternals: Contents**
|
||||
`Redis Internals <#Redis%20Internals>`_
|
||||
`Redis STRINGS <#Redis%20STRINGS>`_
|
||||
`Redis Virtual Memory <#Redis%20Virtual%20Memory>`_
|
||||
`Redis Event Library <#Redis%20Event%20Library>`_
|
||||
RedisInternals
|
||||
==============
|
||||
|
||||
Redis Internals
|
||||
===============
|
||||
|
||||
This is a source code level documentation of Redis.
|
||||
Redis STRINGS
|
||||
-------------
|
||||
|
||||
String is the basic building block of Redis types.
|
||||
Redis is a key-value store. All Redis keys are strings and its also
|
||||
the simplest value type.
|
||||
|
||||
|
||||
Lists, sets, sorted sets and hashes are other more complex value
|
||||
types and even these are composed of strings.
|
||||
`Hacking Strings <HackingStrings.html>`_ documents the Redis String
|
||||
implementation details.
|
||||
Redis Virtual Memory
|
||||
--------------------
|
||||
|
||||
A technical specification full of details about the
|
||||
`Redis Virtual Memory subsystem <VirtualMemorySpecification.html>`_
|
||||
Redis Event Library
|
||||
-------------------
|
||||
|
||||
Read `event library <EventLibray.html>`_ to understand what an
|
||||
event library does and why its needed.
|
||||
`Redis event library <RedisEventLibrary.html>`_ documents the
|
||||
implementation details of the event library used by Redis
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,160 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**RedisPipelining: Contents**
|
||||
`Request/Response protocols and RTT <#Request/Response%20protocols%20and%20RTT>`_
|
||||
`Redis Pipelining <#Redis%20Pipelining>`_
|
||||
`Some benchmark <#Some%20benchmark>`_
|
||||
`Pipelining VS other multi-commands <#Pipelining%20VS%20other%20multi-commands>`_
|
||||
RedisPipelining
|
||||
===============
|
||||
|
||||
Request/Response protocols and RTT
|
||||
==================================
|
||||
|
||||
Redis is a TCP server using the client-server model and what is
|
||||
called a **Request/Response** protocol.
|
||||
This means that usually a request is accomplished with the
|
||||
following steps:
|
||||
|
||||
- The client sends a query to the server, and reads from the
|
||||
socket, usually in a blocking way, for the server response.
|
||||
- The server processes the command and sends the response back to
|
||||
the server.
|
||||
|
||||
So for instance a four commands sequence is something like this:
|
||||
|
||||
- **Client:** INCR X
|
||||
- **Server:** 1
|
||||
- **Client:** INCR X
|
||||
- **Server:** 2
|
||||
- **Client:** INCR X
|
||||
- **Server:** 3
|
||||
- **Client:** INCR X
|
||||
- **Server:** 4
|
||||
|
||||
Clients and Servers are connected via a networking link. Such a
|
||||
link can be very fast (a loopback interface) or very slow (a
|
||||
connection established over the internet with many hops between the
|
||||
two hosts). Whatever the network latency is, there is a time for
|
||||
the packets to travel from the client to the server, and back from
|
||||
the server to the client to carry the reply.
|
||||
This time is called RTT (Round Trip Time). It is very easy to see
|
||||
how this can affect the performances when a client needs to perform
|
||||
many requests in a row (for instance adding many elements to the
|
||||
same list, or populating a database with many keys). For instance
|
||||
if the RTT time is 250 milliseconds (in the case of a very slow
|
||||
link over the internet), even if the server is able to process 100k
|
||||
requests per second, we'll be able to process at max four requests
|
||||
per second.
|
||||
If the interface used is a loopback interface, the RTT is much
|
||||
shorter (for instance my host reports 0,044 milliseconds pinging
|
||||
127.0.0.1), but it is still a lot if you need to perform many
|
||||
writes in a row.
|
||||
Fortunately there is a way to improve this use cases.
|
||||
Redis Pipelining
|
||||
================
|
||||
|
||||
A Request/Response server can be implemented so that it is able to
|
||||
process new requests even if the client didn't already read the old
|
||||
responses. This way it is possible to send **multiple commands** to
|
||||
the server without waiting for the replies at all, and finally read
|
||||
the replies in a single step.
|
||||
This is called pipelining, and is a technique widely in use since
|
||||
many decades. For instance many POP3 protocol implementations
|
||||
already supported this feature, dramatically speeding up the
|
||||
process of downloading new emails from the server.
|
||||
Redis supports pipelining since the very early days, so whatever
|
||||
version you are running, you can use pipelining with Redis. This is
|
||||
an example using the raw netcat utility:
|
||||
::
|
||||
|
||||
$ (echo -en "PING\r\nPING\r\nPING\r\n"; sleep 1) | nc localhost 6379
|
||||
+PONG
|
||||
+PONG
|
||||
+PONG
|
||||
|
||||
This time we are not paying the cost of RTT for every call, but
|
||||
just one time for the three commands.
|
||||
To be very explicit, with pipelining the order of operations of our
|
||||
very first example will be the following:
|
||||
|
||||
- **Client:** INCR X
|
||||
- **Client:** INCR X
|
||||
- **Client:** INCR X
|
||||
- **Client:** INCR X
|
||||
- **Server:** 1
|
||||
- **Server:** 2
|
||||
- **Server:** 3
|
||||
- **Server:** 4
|
||||
|
||||
**IMPORTANT NOTE**: while the client sends commands using
|
||||
pipelining, the server will be forced to queue the replies, using
|
||||
memory. So if you need to send many many commands with pipelining
|
||||
it's better to send this commands up to a given reasonable number,
|
||||
for instance 10k commands, read the replies, and send again other
|
||||
10k commands and so forth. The speed will be nearly the same, but
|
||||
the additional memory used will be at max the amount needed to
|
||||
queue the replies for this 10k commands.
|
||||
Some benchmark
|
||||
==============
|
||||
|
||||
In the following benchmark we'll use the Redis Ruby client,
|
||||
supporting pipelining, to test the speed improvement due to
|
||||
pipelining:
|
||||
::
|
||||
|
||||
require 'rubygems'
|
||||
require 'redis'
|
||||
|
||||
def bench(descr)
|
||||
start = Time.now
|
||||
yield
|
||||
puts "#{descr} #{Time.now-start} seconds"
|
||||
end
|
||||
|
||||
def without_pipelining
|
||||
r = Redis.new
|
||||
10000.times {
|
||||
r.ping
|
||||
}
|
||||
end
|
||||
|
||||
def with_pipelining
|
||||
r = Redis.new
|
||||
r.pipelined {
|
||||
10000.times {
|
||||
r.ping
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
bench("without pipelining") {
|
||||
without_pipelining
|
||||
}
|
||||
bench("with pipelining") {
|
||||
with_pipelining
|
||||
}
|
||||
|
||||
Running the above simple script will provide this figures in my Mac
|
||||
OS X system, running over the loopback interface, where pipelining
|
||||
will provide the smallest improvement as the RTT is already pretty
|
||||
low:
|
||||
::
|
||||
|
||||
without pipelining 1.185238 seconds
|
||||
with pipelining 0.250783 seconds
|
||||
|
||||
As you can see using pipelining we improved the transfer by a
|
||||
factor of five.
|
||||
Pipelining VS other multi-commands
|
||||
==================================
|
||||
|
||||
Often we get requests about adding new commands performing multiple
|
||||
operations in a single pass. For instance there is no command to
|
||||
add multiple elements in a set. You need calling many times SADD.
|
||||
With pipelining you can have performances near to an MSADD command,
|
||||
but at the same time we'll avoid bloating the Redis command set
|
||||
with too many commands. An additional advantage is that the version
|
||||
written using just SADD will be ready for a distributed environment
|
||||
(for instance Redis Cluster, that is in the process of being
|
||||
developed) just dropping the pipelining code.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,94 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**RedisStatus: Contents**
|
||||
`Redis Status Page <#Redis%20Status%20Page>`_
|
||||
`How stable are the alpha previews? <#How%20stable%20are%20the%20alpha%20previews?>`_
|
||||
`How to obtain a 2.2-alpha preview <#How%20to%20obtain%20a%202.2-alpha%20preview>`_
|
||||
`ETA for Redis 2.2? <#ETA%20for%20Redis%202.2?>`_
|
||||
`When will we be able to see a working version of Redis Cluster? <#When%20will%20we%20be%20able%20to%20see%20a%20working%20version%20of%20Redis%20Cluster?>`_
|
||||
RedisStatus
|
||||
===========
|
||||
|
||||
Redis Status Page
|
||||
=================
|
||||
|
||||
Hello! Redis uses versions composed of three numbers separated by a
|
||||
dot: **major**.**minor**.**patchlevel**.
|
||||
When the **minor** is an odd number, it is used for an unstable
|
||||
release, so stable releases are for instance 1.2, 2.0, and so
|
||||
forth.
|
||||
This is the status of the different Redis versions currently
|
||||
available:
|
||||
|
||||
- 1.2 is the **legacy redis stable release**, now it is completely
|
||||
obsoleted by Redis 2.0. Redis 2.0 is almost completely back
|
||||
compatible with 1.2 so upgrading is usually not a problem. Still
|
||||
1.2 is believed to be a very stable release that works well, so if
|
||||
you are using it in production with code that probably will not
|
||||
modified to use more advanced Redis features available in 2.0, it
|
||||
makes sense to take 1.2 running. For everything new, it's better to
|
||||
start with 2.0.
|
||||
|
||||
|
||||
- 2.0 is the current **stable release**. It is better than 1.2 in
|
||||
more or less everything: more features, more mature code, better
|
||||
replication, better persistence, and so forth. It is currently what
|
||||
most users should use, unless they really need features that are
|
||||
only available into an **unstable** release.
|
||||
|
||||
|
||||
- 2.1 is the current **unstable release**, and there are no tar.gz
|
||||
for this release, you need to download it from git. **Warning:**
|
||||
the master branch in git may work most of the time but is NOT what
|
||||
you should use. What's better instead is to use the 2.2-alpha tags:
|
||||
every time Redis 2.1.x is stable enough and the new features merged
|
||||
passed all the tests for a couple of weeks, and we didn't received
|
||||
severe bug reports from users, we tag master as 2.2-alpha *number*,
|
||||
where *number* is simply a progressive number. Just pick this
|
||||
number.
|
||||
|
||||
How stable are the alpha previews?
|
||||
==================================
|
||||
|
||||
Well it is surely ok for development, but it is not recommended for
|
||||
production. Still there are many users that trust Redis development
|
||||
process so much to use alpha releases in production, but this is up
|
||||
to you, we don't give any guarantee ;)
|
||||
How to obtain a 2.2-alpha preview
|
||||
=================================
|
||||
|
||||
Simply using git:
|
||||
::
|
||||
|
||||
$ git clone git://github.com/antirez/redis.git
|
||||
Initialized empty Git repository in /tmp/redis/.git/
|
||||
...
|
||||
|
||||
Then you can list all the branches matching 2.1-alpha with:
|
||||
::
|
||||
|
||||
cd redis
|
||||
$ git tag | grep 2.2-alpha
|
||||
2.2-alpha0
|
||||
2.2-alpha1
|
||||
2.2-alpha2
|
||||
|
||||
At this point you can just use **git checkout *tagname***,
|
||||
substituting *tagname* with 2.2-alphaX where X is the greater
|
||||
progressive number you see in the listing.
|
||||
ETA for Redis 2.2?
|
||||
==================
|
||||
|
||||
Redis 2.2 is planned to enter the release candidate stage before
|
||||
the end of the 2010.
|
||||
When will we be able to see a working version of Redis Cluster?
|
||||
===============================================================
|
||||
|
||||
I'm already working at it, I mean not just designing, but writing
|
||||
code. In three months we should have some kind of experimental
|
||||
version, while in six months we should have the first release
|
||||
candidate.
|
||||
Probably the first **stable** release of Redis with working cluster
|
||||
will be called 3.0, but I'll try to merge it into 2.2 as an
|
||||
experimental support if we'll be sure there is no impact in the
|
||||
stability of the system when clustering is not used.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,154 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**Redis\_1\_2\_0\_Changelog: Contents**
|
||||
`What's new in Redis 1.2 <#What's%20new%20in%20Redis%201.2>`_
|
||||
`New persistence mode: Append Only File <#New%20persistence%20mode:%20Append%20Only%20File>`_
|
||||
`New data type: sorted sets <#New%20data%20type:%20sorted%20sets>`_
|
||||
`Specialized integer objects encoding <#Specialized%20integer%20objects%20encoding>`_
|
||||
`MSET and MSETNX <#MSET%20and%20MSETNX>`_
|
||||
`Better Performances <#Better%20Performances>`_
|
||||
`Solaris Support <#Solaris%20Support>`_
|
||||
`Support for the new generation protocol <#Support%20for%20the%20new%20generation%20protocol>`_
|
||||
`A few new commands about already supported data types <#A%20few%20new%20commands%20about%20already%20supported%20data%20types>`_
|
||||
`Bug fixing <#Bug%20fixing>`_
|
||||
`CHANGELOG for Redis 1.1.90 <#CHANGELOG%20for%20Redis%201.1.90>`_
|
||||
Redis\_1\_2\_0\_Changelog
|
||||
=========================
|
||||
|
||||
What's new in Redis 1.2
|
||||
=======================
|
||||
|
||||
New persistence mode: Append Only File
|
||||
--------------------------------------
|
||||
|
||||
The Append Only File is an alternative way to save your data in
|
||||
Redis that is fully durable! Unlike the snapshotting (default)
|
||||
persistence mode, where the database is saved asynchronously from
|
||||
time to time, the Append Only File saves every change ASAP in a
|
||||
text-only file that works like a journal. Redis will play back this
|
||||
file again at startup reloading the whole dataset back in memory.
|
||||
Redis Append Only File supports background Log compaction. For more
|
||||
info read the `Append Only File HOWTO <AppendOnlyFileHowto.html>`_.
|
||||
New data type: sorted sets
|
||||
--------------------------
|
||||
|
||||
Sorted sets are collections of elements (like Sets) with an
|
||||
associated score (in the form of a double precision floating point
|
||||
number). Elements in a sorted set are taken in order, so for
|
||||
instance to take the greatest element is an O(1) operation.
|
||||
Insertion and deletion is O(log(N)). Sorted sets are implemented
|
||||
using a dual ported data structure consisting of an hash table and
|
||||
a skip list. For more information please read the
|
||||
`Introduction To Redis Data Types <IntroductionToRedisDataTypes.html>`_.
|
||||
Specialized integer objects encoding
|
||||
------------------------------------
|
||||
|
||||
Redis 1.2 will use less memory than Redis 1.0 for values in
|
||||
Strings, Lists or Sets elements that happen to be representable as
|
||||
32 or 64 bit signed integers (it depends on your arch bits for the
|
||||
long C type). This is totally transparent form the point of view of
|
||||
the user, but will safe a lot of memory (30% less in datasets where
|
||||
there are many integers).
|
||||
MSET and MSETNX
|
||||
---------------
|
||||
|
||||
That is, setting multiple keys in one command, atomically. For more
|
||||
information see the `MSET command <MsetCommand.html>`_ wiki page.
|
||||
Better Performances
|
||||
-------------------
|
||||
|
||||
|
||||
- 100x times faster SAVE and BGSAVE! There was a problem in the
|
||||
LZF lib configuration that is now resolved. The effect is this
|
||||
impressive speedup. Also the saving child will no longer use 100%
|
||||
of CPU.
|
||||
- Glue output buffer and writev(). Many commands producing large
|
||||
outputs, like LRANGE, will now be even 10 times faster, thanks to
|
||||
the new output buffer gluing algorithm and the (optional) use of
|
||||
writev(2) syscall.
|
||||
- Support for epool and kqueue / kevent. 10,000 clients
|
||||
scalability.
|
||||
- Much better EXPIRE support, now it's possible to work with very
|
||||
large sets of keys expiring in very short time without to incur in
|
||||
memory problems (the new algorithm expires keys in an adaptive way,
|
||||
so will get more aggressive if there are a lot of expiring keys)
|
||||
|
||||
Solaris Support
|
||||
---------------
|
||||
|
||||
Redis will now compile and work on Solaris without problems.
|
||||
Warning: the Solaris user base is very little, so Redis running on
|
||||
Solaris may not be as tested and stable as it is on Linux and Mac
|
||||
OS X.
|
||||
Support for the new generation protocol
|
||||
---------------------------------------
|
||||
|
||||
|
||||
- Redis is now able to accept commands in a new fully binary safe
|
||||
way: with the new protocol keys are binary safe, not only values,
|
||||
and there is no distinction between bulk commands and inline
|
||||
commands. This new protocol is currently used only for MSET and
|
||||
MSETNX but at some point it will hopefully replace the old one. See
|
||||
the Multi Bulk Commands section in the
|
||||
`Redis Protocol Specification <ProtocolSpecification.html>`_ for
|
||||
more information.
|
||||
|
||||
A few new commands about already supported data types
|
||||
-----------------------------------------------------
|
||||
|
||||
|
||||
- `SRANDMEMBER <SrandmemberCommand.html>`_
|
||||
- The `SortCommand <SortCommand.html>`_ is now supprots the
|
||||
**STORE** and **GET #** forms, the first can be used to save sorted
|
||||
lists, sets or sorted sets into keys for caching. Check the manual
|
||||
page for more information about the **GET #** form.
|
||||
- The new `RPOPLPUSH command <RpoplpushCommand.html>`_ can do many
|
||||
interesting magics, and a few of this are documented in the wiki
|
||||
page of the command.
|
||||
|
||||
Bug fixing
|
||||
----------
|
||||
|
||||
Of course, many bugs are now fixed, and I bet, a few others
|
||||
introduced: this is how software works after all, so make sure to
|
||||
report issues in the Redis mailing list or in the Google Code
|
||||
issues tracker.
|
||||
Enjoy! antirez
|
||||
CHANGELOG for Redis 1.1.90
|
||||
==========================
|
||||
|
||||
|
||||
- 2009-09-10 in-memory specialized object encoding. (antirez)
|
||||
- 2009-09-17 maxmemory fixed in 64 systems for values > 4GB.
|
||||
(antirez)
|
||||
- 2009-10-07 multi-bulk protocol implemented. (antriez)
|
||||
- 2009-10-16 MSET and MSETNX commands implemented (antirez)
|
||||
- 2009-10-21 SRANDMEMBER added (antirez)
|
||||
- 2009-10-23 Fixed compilation in mac os x snow leopard when
|
||||
compiling a 32 bit binary. (antirez)
|
||||
- 2009-10-23 New data type: Sorted sets and Z-commands (antirez)
|
||||
- 2009-10-26 Solaris fixed (Alan Harder)
|
||||
- 2009-10-29 Fixed Issue a number of open issues (antirez)
|
||||
- 2009-10-30 New persistence mode: append only file (antirez)
|
||||
- 2009-11-01 SORT STORE option (antirez)
|
||||
- 2009-11-03 redis-cli now accepts a -r (repeat) switch. (antirez)
|
||||
- 2009-11-04 masterauth option merged (Anthony Lauzon)
|
||||
- 2009-11-04 redis-test is now a better Redis citizen, testing
|
||||
everything against DB 9 and 10 and only if this DBs are empty.
|
||||
(antirez)
|
||||
- 2009-11-10 Implemented a much better lazy expiring algorithm for
|
||||
EXPIRE (antirez)
|
||||
- 2009-11-11 RPUSHLPOP (antirez from an idea of @ezmobius)
|
||||
- 2009-11-12 Merge git://github.com/ianxm/redis (Can't remmber
|
||||
what this implements, sorry)
|
||||
- 2009-11-17 multi-bulk reply support for redis-bench, LRANGE
|
||||
speed tests (antirez)
|
||||
- 2009-11-17 support for writev implemented. (Stefano Barbato)
|
||||
- 2009-11-19 debug mode (-D) in redis-bench (antirez)
|
||||
- 2009-11-21 SORT GET # implemented (antirez)
|
||||
- 2009-11-23 ae.c made modular, with support for epoll. (antirez)
|
||||
- 2009-11-26 background append log rebuilding (antirez)
|
||||
- 2009-11-28 Added support for kqueue. (Harish Mallipeddi)
|
||||
- 2009-11-29 SORT support for sorted sets (antirez, thanks to
|
||||
@tobi for the idea)
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,120 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**Redis\_2\_0\_0\_Changelog: Contents**
|
||||
`Redis 2.0: What's new? <#Redis%202.0:%20What's%20new?>`_
|
||||
`MULTI/EXEC <#MULTI/EXEC>`_
|
||||
`Blocking pop <#Blocking%20pop>`_
|
||||
`Publish/subscribe <#Publish/subscribe>`_
|
||||
`Hashes <#Hashes>`_
|
||||
`Virtual Memory <#Virtual%20Memory>`_
|
||||
`Contributors <#Contributors>`_
|
||||
`Special Thanks <#Special%20Thanks>`_
|
||||
`DOWNLOAD <#DOWNLOAD>`_
|
||||
Redis\_2\_0\_0\_Changelog
|
||||
=========================
|
||||
|
||||
Redis 2.0: What's new?
|
||||
======================
|
||||
|
||||
The release of Redis 2.0 marks a major milestone in Redis
|
||||
development. Apart from an endless list of new features, there are
|
||||
some major ones that deserve to be highlighted.
|
||||
It's worth to mention that while Redis 2.0.0 just reached its first
|
||||
stable release, Redis 2.2.0 is near to reach feature freeze, so ...
|
||||
be prepared for new exiting things in very short time!
|
||||
MULTI/EXEC
|
||||
~~~~~~~~~~
|
||||
|
||||
The MULTI/EXEC family of commands were added to fulfill the need to
|
||||
execute multiple commands as a single atomic block. Because all
|
||||
commands inside a MULTI/EXEC block are serialized and executed
|
||||
sequentially, it is not possible that another client request is
|
||||
served in the middle of executing this block. All commands are
|
||||
executed one after the other when EXEC is called, which makes sure
|
||||
either **all** or **no** commands are executed, independent of the
|
||||
state of the client connection.
|
||||
More on MULTI/EXEC:
|
||||
|
||||
- `http://code.google.com/p/redis/wiki/MultiExecCommand <http://code.google.com/p/redis/wiki/MultiExecCommand>`_
|
||||
|
||||
Note that WATCH, a CAS (check and set) variant of MULTI/EXEC will
|
||||
be available on 2.2.0 and is not part of 2.0.0.
|
||||
Blocking pop
|
||||
~~~~~~~~~~~~
|
||||
|
||||
The commands BLPOP and BRPOP were added to support popping from a
|
||||
list in a blocking fashion. This means the client connection will
|
||||
be blocked for a certain amount of time until another client pushes
|
||||
an item on a list. These commands are frequently used in
|
||||
producer/consumer scenarios.
|
||||
More on blocking pop:
|
||||
|
||||
- `http://code.google.com/p/redis/wiki/BlpopCommand <http://code.google.com/p/redis/wiki/BlpopCommand>`_
|
||||
|
||||
Publish/subscribe
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
The family of publish/subscribe commands let clients publish
|
||||
messages onto channels and subscribe to receive all messages that
|
||||
are published on channels. Also included are commands to receive
|
||||
all messages for which the channel matches a given pattern.
|
||||
More on publish/subscribe:
|
||||
|
||||
- `http://code.google.com/p/redis/wiki/PublishSubscribe <http://code.google.com/p/redis/wiki/PublishSubscribe>`_
|
||||
- `http://antirez.com/post/redis-weekly-update-3-publish-submit.html <http://antirez.com/post/redis-weekly-update-3-publish-submit.html>`_
|
||||
- `http://rediscookbook.org/pubsub\_for\_asynchronous\_communication.html <http://rediscookbook.org/pubsub_for_asynchronous_communication.html>`_
|
||||
|
||||
Hashes
|
||||
~~~~~~
|
||||
|
||||
This new datatype allows to store multiple key/value pairs on a
|
||||
single key. Together with the list of regular commands you would
|
||||
expect for such a datatype (HSET, HGET, HDEL, HLEN, HKEYS, ...), it
|
||||
is also possible to use the values *inside* a hash for any SORT
|
||||
operation.
|
||||
More on hashes:
|
||||
|
||||
- `http://code.google.com/p/redis/wiki/HsetCommand <http://code.google.com/p/redis/wiki/HsetCommand>`_
|
||||
- `http://antirez.com/post/redis-weekly-update-1.html <http://antirez.com/post/redis-weekly-update-1.html>`_
|
||||
|
||||
Virtual Memory
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Redis Virtual Memory allows users to grow their dataset beyond the
|
||||
limits of their RAM.
|
||||
More on virtual memory:
|
||||
|
||||
- `http://code.google.com/p/redis/wiki/VirtualMemoryUserGuide <http://code.google.com/p/redis/wiki/VirtualMemoryUserGuide>`_
|
||||
- `http://antirez.com/post/redis-virtual-memory-story.html <http://antirez.com/post/redis-virtual-memory-story.html>`_
|
||||
|
||||
Contributors
|
||||
~~~~~~~~~~~~
|
||||
|
||||
|
||||
- Salvatore Sanfilippo
|
||||
- Pieter Noordhuis
|
||||
- Antonio Ognio
|
||||
- Alex McHale
|
||||
- Michel Martens
|
||||
- Damian Janowski
|
||||
- Bruno Deferrari
|
||||
- Ashley Martens
|
||||
- Derek Collison
|
||||
- Damian Janowski
|
||||
- Jeremy Zawodny
|
||||
- Konstantin Merenkov
|
||||
- Michel Martens
|
||||
- Sam Hendley
|
||||
|
||||
Special Thanks
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Thanks to VMware sponsoring the work of Salvatore and Pieter, and
|
||||
the Redis community of users and client library developers. Redis
|
||||
2.0.0 was possible only thanks to your support.
|
||||
DOWNLOAD
|
||||
~~~~~~~~
|
||||
|
||||
You can grab Redis 2.0.0 from
|
||||
`Google Code <http://code.google.com/p/redis/downloads/list>`_.
|
||||
It is also tagged on Git.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,101 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**Redis\_2\_0\_Whats\_new: Contents**
|
||||
`Redis 2.0: What's new? <#Redis%202.0:%20What's%20new?>`_
|
||||
`MULTI/EXEC <#MULTI/EXEC>`_
|
||||
`Blocking pop <#Blocking%20pop>`_
|
||||
`Publish/subscribe <#Publish/subscribe>`_
|
||||
`Hashes <#Hashes>`_
|
||||
`Virtual Memory <#Virtual%20Memory>`_
|
||||
`Contributors <#Contributors>`_
|
||||
Redis\_2\_0\_Whats\_new
|
||||
=======================
|
||||
|
||||
Redis 2.0: What's new?
|
||||
======================
|
||||
|
||||
The release of Redis 2.0 marks a major milestone in Redis
|
||||
development. Apart from an endless list of new features, there are
|
||||
some major ones that deserve to be highlighted.
|
||||
MULTI/EXEC
|
||||
~~~~~~~~~~
|
||||
|
||||
The MULTI/EXEC family of commands were added to fulfill the need to
|
||||
execute multiple commands as a single atomic block. Because all
|
||||
commands inside a MULTI/EXEC block are serialized and executed
|
||||
sequentially, it is not possible that another client request is
|
||||
served in the middle of executing this block. All commands are
|
||||
executed one after the other when EXEC is called, which makes sure
|
||||
either **all** or **no** commands are executed, independent of the
|
||||
state of the client connection.
|
||||
More on MULTI/EXEC:
|
||||
|
||||
- `http://code.google.com/p/redis/wiki/MultiExecCommand <http://code.google.com/p/redis/wiki/MultiExecCommand>`_
|
||||
|
||||
Blocking pop
|
||||
~~~~~~~~~~~~
|
||||
|
||||
The commands BLPOP and BRPOP were added to support popping from a
|
||||
list in a blocking fashion. This means the client connection will
|
||||
be blocked for a certain amount of time until another client pushes
|
||||
an item on a list. These commands are frequently used in
|
||||
producer/consumer scenarios.
|
||||
More on blocking pop:
|
||||
|
||||
- `http://code.google.com/p/redis/wiki/BlpopCommand <http://code.google.com/p/redis/wiki/BlpopCommand>`_
|
||||
|
||||
Publish/subscribe
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
The family of publish/subscribe commands let clients publish
|
||||
messages onto channels and subscribe to receive all messages that
|
||||
are published on channels. Also included are commands to receive
|
||||
all messages for which the channel matches a given pattern.
|
||||
More on publish/subscribe:
|
||||
|
||||
- `http://code.google.com/p/redis/wiki/PublishSubscribe <http://code.google.com/p/redis/wiki/PublishSubscribe>`_
|
||||
- `http://antirez.com/post/redis-weekly-update-3-publish-submit.html <http://antirez.com/post/redis-weekly-update-3-publish-submit.html>`_
|
||||
- `http://rediscookbook.org/pubsub\_for\_asynchronous\_communication.html <http://rediscookbook.org/pubsub_for_asynchronous_communication.html>`_
|
||||
|
||||
Hashes
|
||||
~~~~~~
|
||||
|
||||
This new datatype allows to store multiple key/value pairs on a
|
||||
single key. Together with the list of regular commands you would
|
||||
expect for such a datatype (HSET, HGET, HDEL, HLEN, HKEYS, ...), it
|
||||
is also possible to use the values *inside* a hash for any SORT
|
||||
operation.
|
||||
More on hashes:
|
||||
|
||||
- `http://code.google.com/p/redis/wiki/HsetCommand <http://code.google.com/p/redis/wiki/HsetCommand>`_
|
||||
- `http://antirez.com/post/redis-weekly-update-1.html <http://antirez.com/post/redis-weekly-update-1.html>`_
|
||||
|
||||
Virtual Memory
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Redis Virtual Memory allows users to grow their dataset beyond the
|
||||
limits of their RAM.
|
||||
More on virtual memory:
|
||||
|
||||
- `http://code.google.com/p/redis/wiki/VirtualMemoryUserGuide <http://code.google.com/p/redis/wiki/VirtualMemoryUserGuide>`_
|
||||
- `http://antirez.com/post/redis-virtual-memory-story.html <http://antirez.com/post/redis-virtual-memory-story.html>`_
|
||||
|
||||
Contributors
|
||||
------------
|
||||
|
||||
|
||||
- Salvatore Sanfilippo
|
||||
- Pieter Noordhuis
|
||||
- Antonio Ognio
|
||||
- Alex McHale
|
||||
- Michel Martens
|
||||
- Damian Janowski
|
||||
- Bruno Deferrari
|
||||
- Ashley Martens
|
||||
- Derek Collison
|
||||
- Damian Janowski
|
||||
- Jeremy Zawodny
|
||||
- Konstantin Merenkov
|
||||
- Michel Martens
|
||||
- Sam Hendley
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,21 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**RenameCommand: Contents**
|
||||
`RENAME \_oldkey\_ \_newkey\_ <#RENAME%20_oldkey_%20_newkey_>`_
|
||||
`Return value <#Return%20value>`_
|
||||
RenameCommand
|
||||
=============
|
||||
|
||||
#sidebar `GenericCommandsSidebar <GenericCommandsSidebar.html>`_
|
||||
RENAME \_oldkey\_ \_newkey\_
|
||||
============================
|
||||
|
||||
*Time complexity: O(1)*
|
||||
Atomically renames the key *oldkey* to *newkey*. If the source
|
||||
anddestination name are the same an error is returned. If
|
||||
*newkey*already exists it is overwritten.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Status code repy <ReplyTypes.html>`_
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,25 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**RenamenxCommand: Contents**
|
||||
`RENAMENX \_oldkey\_ \_newkey\_ <#RENAMENX%20_oldkey_%20_newkey_>`_
|
||||
`Return value <#Return%20value>`_
|
||||
RenamenxCommand
|
||||
===============
|
||||
|
||||
#sidebar `GenericCommandsSidebar <GenericCommandsSidebar.html>`_
|
||||
RENAMENX \_oldkey\_ \_newkey\_
|
||||
==============================
|
||||
|
||||
*Time complexity: O(1)*
|
||||
Rename *oldkey* into *newkey* but fails if the destination key
|
||||
*newkey* already exists.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Integer reply <ReplyTypes.html>`_, specifically:
|
||||
::
|
||||
|
||||
1 if the key was renamed
|
||||
0 if the target key already exist
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,75 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**ReplicationHowto: Contents**
|
||||
`Redis Replication Howto <#Redis%20Replication%20Howto>`_
|
||||
`General Information <#General%20Information>`_
|
||||
`How Redis replication works <#How%20Redis%20replication%20works>`_
|
||||
`Configuration <#Configuration>`_
|
||||
ReplicationHowto
|
||||
================
|
||||
|
||||
#sidebar `RedisGuides <RedisGuides.html>`_
|
||||
Redis Replication Howto
|
||||
=======================
|
||||
|
||||
General Information
|
||||
-------------------
|
||||
|
||||
Redis replication is a very simple to use and configure
|
||||
master-slave replication that allows slave Redis servers to be
|
||||
exact copies of master servers. The following are some very
|
||||
important facts about Redis replication:
|
||||
|
||||
- A master can have multiple slaves.
|
||||
- Slaves are able to accept other slaves connections, so instead
|
||||
to connect a number of slaves against the same master it is also
|
||||
possible to connect some of the slaves to other slaves in a
|
||||
graph-alike structure.
|
||||
- Redis replication is non-blocking on the master side, this means
|
||||
that the master will continue to serve queries while one or more
|
||||
slaves are performing the first synchronization. Instead
|
||||
replication is blocking on the slave side: while the slave is
|
||||
performing the first synchronization it can't reply to queries.
|
||||
- Replications can be used both for scalability, in order to have
|
||||
multiple slaves for read-only queries (for example heavy
|
||||
`SORT <SortCommand.html>`_ operations can be launched against
|
||||
slaves), or simply for data redundancy.
|
||||
- It is possible to use replication to avoid the saving process on
|
||||
the master side: just configure your master redis.conf in order to
|
||||
avoid saving at all (just comment al the "save" directives), then
|
||||
connect a slave configured to save from time to time.
|
||||
|
||||
How Redis replication works
|
||||
---------------------------
|
||||
|
||||
In order to start the replication, or after the connection closes
|
||||
in order resynchronize with the master, the slave connects to the
|
||||
master and issues the SYNC command.
|
||||
The master starts a background saving, and at the same time starts
|
||||
to collect all the new commands received that had the effect to
|
||||
modify the dataset. When the background saving completed the master
|
||||
starts the transfer of the database file to the slave, that saves
|
||||
it on disk, and then load it in memory. At this point the master
|
||||
starts to send all the accumulated commands, and all the new
|
||||
commands received from clients that had the effect of a dataset
|
||||
modification, to the slave, as a stream of commands, in the same
|
||||
format of the Redis protocol itself.
|
||||
You can try it yourself via telnet. Connect to the Redis port while
|
||||
the server is doing some work and issue the SYNC command. You'll
|
||||
see a bulk transfer and then every command received by the master
|
||||
will be re-issued in the telnet session.
|
||||
Slaves are able to automatically reconnect when the master ``<->``
|
||||
slave link goes down for some reason. If the master receives
|
||||
multiple concurrent slave synchronization requests it performs a
|
||||
single background saving in order to serve all them.
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
To configure replication is trivial: just add the following line to
|
||||
the slave configuration file:
|
||||
::
|
||||
|
||||
slaveof 192.168.1.1 6379
|
||||
|
||||
Of course you need to replace 192.168.1.1 6379 with your master ip
|
||||
address (or hostname) and port.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,72 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**ReplyTypes: Contents**
|
||||
`Redis Reply Types <#Redis%20Reply%20Types>`_
|
||||
`Status code reply <#Status%20code%20reply>`_
|
||||
`Error reply <#Error%20reply>`_
|
||||
`Integer reply <#Integer%20reply>`_
|
||||
`Bulk reply <#Bulk%20reply>`_
|
||||
`Multi bulk reply <#Multi%20bulk%20reply>`_
|
||||
ReplyTypes
|
||||
==========
|
||||
|
||||
Redis Reply Types
|
||||
=================
|
||||
|
||||
Redis commands can reply to the client with four different kind of
|
||||
replies, you can find the protocol level specification of this
|
||||
replies in the
|
||||
`Redis Protocol Specification <ProtocolSpecification.html>`_. This
|
||||
page is instead an higher level description of the four types of
|
||||
replies from the point of view of the final user.
|
||||
Status code reply
|
||||
=================
|
||||
|
||||
Status code replies are single line strings having the **+**
|
||||
character as first byte. The string to return to the client is
|
||||
simply verything that follows the first **+** character. For
|
||||
example the `PING <PingCommand.html>`_ command returns **+PONG**,
|
||||
that is the string "PONG".
|
||||
Error reply
|
||||
===========
|
||||
|
||||
This is like a status code reply but the first character is **-**
|
||||
instead of **+**. The client library should raise an error for
|
||||
error replies and stop the execution of the program if the
|
||||
exception is not trapped, showing the error message (everything
|
||||
following the first **-** character). An example of error is
|
||||
"-Error no such key" or "-foobar". Note that error replies will not
|
||||
collide with negative integer replies since integer replies are
|
||||
prefixed with the **:** character.
|
||||
Integer reply
|
||||
=============
|
||||
|
||||
At protocol level integer replies are single line replies in form
|
||||
of a decimal singed number prefixed by a **:** character. For
|
||||
example **:10** is an integer reply. Redis commands returning
|
||||
*true* or *false* will use an integer reply with 0 or 1 as values
|
||||
where 0 is false and 1 is true.
|
||||
Integer replies are usually passed by client libraries as integer
|
||||
values.
|
||||
Bulk reply
|
||||
==========
|
||||
|
||||
A bulk reply is a binary-safe reply that is used to return a binary
|
||||
safe single string value (string is not limited to alphanumerical
|
||||
strings, it may contain binary data of any kind). Client libraries
|
||||
will usually return a string as return value of Redis commands
|
||||
returning bulk replies. There is a special bulk reply that signal
|
||||
that the element does not exist. When this happens the client
|
||||
library should return 'nil', 'false', or some other special element
|
||||
that can be distinguished by an empty string.
|
||||
Multi bulk reply
|
||||
================
|
||||
|
||||
While a bulk reply returns a single string value, multi bulk
|
||||
replies are used to return multiple values: lists, sets, and so on.
|
||||
Elements of a bulk reply can be missing. Client libraries should
|
||||
return 'nil' or 'false' in order to make this elements
|
||||
distinguishable from empty strings. Client libraries should return
|
||||
multi bulk replies that are about ordered elements like list ranges
|
||||
as lists, and bulk replies about sets as hashes or Sets if the
|
||||
implementation language has a Set type.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,37 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**RoadMap: Contents**
|
||||
`Road Map (ROUGH DRAFT) <#Road%20Map%20(ROUGH%20DRAFT)>`_
|
||||
`Features added in past versions <#Features%20added%20in%20past%20versions>`_
|
||||
`1.1 / 1.2 <#1.1%20/%201.2>`_
|
||||
`0.x / 1.0 <#0.x%20/%201.0>`_
|
||||
RoadMap
|
||||
=======
|
||||
|
||||
Road Map (ROUGH DRAFT)
|
||||
======================
|
||||
|
||||
The up to date, raw Road Map for Redis is part of the source code,
|
||||
you can find it here:
|
||||
`http://github.com/antirez/redis/raw/master/TODO <http://github.com/antirez/redis/raw/master/TODO>`_
|
||||
Features added in past versions
|
||||
-------------------------------
|
||||
|
||||
1.1 / 1.2
|
||||
---------
|
||||
|
||||
|
||||
- `Ordered Set (ZSET) <DataTypes.html>`_
|
||||
- `Multibulk Commands <MultiBulkCommands.html>`_
|
||||
- In memory integer encoding of `integers <DataTypes.html>`_.
|
||||
Memory saving of 20% or more with datasets using high number of
|
||||
integer IDs.
|
||||
- Enhanced `EXPIRE <ExpireCommand.html>`_ algorithm.
|
||||
|
||||
0.x / 1.0
|
||||
---------
|
||||
|
||||
|
||||
- TODO: Add 1.0 Features. This is important for clarity in
|
||||
`SupportedLanguages <SupportedLanguages.html>`_
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,63 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**RpoplpushCommand: Contents**
|
||||
`RPOPLPUSH \_srckey\_ \_dstkey\_ (Redis > <#RPOPLPUSH%20_srckey_%20_dstkey_%20(Redis%20%3E>`_
|
||||
`Programming patterns: safe queues <#Programming%20patterns:%20safe%20queues>`_
|
||||
`Programming patterns: server-side O(N) list traversal <#Programming%20patterns:%20server-side%20O(N)%20list%20traversal>`_
|
||||
`Return value <#Return%20value>`_
|
||||
RpoplpushCommand
|
||||
================
|
||||
|
||||
#sidebar `ListCommandsSidebar <ListCommandsSidebar.html>`_
|
||||
RPOPLPUSH \_srckey\_ \_dstkey\_ (Redis >
|
||||
========================================
|
||||
|
||||
1.1) = *Time complexity: O(1)*
|
||||
Atomically return and remove the last (tail) element of the
|
||||
*srckey* list,and push the element as the first (head) element of
|
||||
the *dstkey* list. Forexample if the source list contains the
|
||||
elements "a","b","c" and thedestination list contains the elements
|
||||
"foo","bar" after an RPOPLPUSH commandthe content of the two lists
|
||||
will be "a","b" and "c","foo","bar".
|
||||
|
||||
If the *key* does not exist or the list is already empty the
|
||||
specialvalue 'nil' is returned. If the *srckey* and *dstkey* are
|
||||
the same theoperation is equivalent to removing the last element
|
||||
from the list and pusingit as first element of the list, so it's a
|
||||
"list rotation" command.
|
||||
|
||||
Programming patterns: safe queues
|
||||
---------------------------------
|
||||
|
||||
Redis lists are often used as queues in order to exchange messages
|
||||
betweendifferent programs. A program can add a message performing
|
||||
an `LPUSH <RpushCommand.html>`_ operationagainst a Redis list (we
|
||||
call this program a Producer), while another program(that we call
|
||||
Consumer) can process the messages performing an
|
||||
`RPOP <LpopCommand.html>`_ commandin order to start reading the
|
||||
messages from the oldest.
|
||||
|
||||
Unfortunately if a Consumer crashes just after an
|
||||
`RPOP <LpopCommand.html>`_ operation the messagegets lost.
|
||||
RPOPLPUSH solves this problem since the returned message isadded to
|
||||
another "backup" list. The Consumer can later remove the
|
||||
messagefrom the backup list using the `LREM <LremCommand.html>`_
|
||||
command when the message was correctlyprocessed.
|
||||
|
||||
Another process, called Helper, can monitor the "backup" list to
|
||||
check fortimed out entries to repush against the main queue.
|
||||
|
||||
Programming patterns: server-side O(N) list traversal
|
||||
-----------------------------------------------------
|
||||
|
||||
Using RPOPPUSH with the same source and destination key a process
|
||||
canvisit all the elements of an N-elements List in O(N) without to
|
||||
transferthe full list from the server to the client in a single
|
||||
`LRANGE <LrangeCommand.html>`_ operation.Note that a process can
|
||||
traverse the list even while other processesare actively RPUSHing
|
||||
against the list, and still no element will be skipped.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Bulk reply <ReplyTypes.html>`_
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,27 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**RpushCommand: Contents**
|
||||
`RPUSH \_key\_ \_string\_ <#RPUSH%20_key_%20_string_>`_
|
||||
`LPUSH \_key\_ \_string\_ <#LPUSH%20_key_%20_string_>`_
|
||||
`Return value <#Return%20value>`_
|
||||
RpushCommand
|
||||
============
|
||||
|
||||
#sidebar `ListCommandsSidebar <ListCommandsSidebar.html>`_
|
||||
RPUSH \_key\_ \_string\_
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
LPUSH \_key\_ \_string\_
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
*Time complexity: O(1)*
|
||||
Add the *string* value to the head (LPUSH) or tail (RPUSH) of the
|
||||
liststored at *key*. If the key does not exist an empty list is
|
||||
created just beforethe append operation. If the key exists but is
|
||||
not a List an erroris returned.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Integer reply <ReplyTypes.html>`_, specifically, the number of
|
||||
elements inside the list after the push operation.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,28 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**SaddCommand: Contents**
|
||||
`SADD \_key\_ \_member\_ <#SADD%20_key_%20_member_>`_
|
||||
`Return value <#Return%20value>`_
|
||||
SaddCommand
|
||||
===========
|
||||
|
||||
#sidebar `SetCommandsSidebar <SetCommandsSidebar.html>`_
|
||||
SADD \_key\_ \_member\_
|
||||
=======================
|
||||
|
||||
*Time complexity O(1)*
|
||||
Add the specified *member* to the set value stored at *key*. If
|
||||
*member*is already a member of the set no operation is performed.
|
||||
If *key*does not exist a new set with the specified *member* as
|
||||
sole member iscreated. If the key exists but does not hold a set
|
||||
value an error isreturned.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Integer reply <ReplyTypes.html>`_, specifically:
|
||||
::
|
||||
|
||||
1 if the new element was added
|
||||
0 if the element was already a member of the set
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,27 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**SaveCommand: Contents**
|
||||
`SAVE <#SAVE>`_
|
||||
`Return value <#Return%20value>`_
|
||||
SaveCommand
|
||||
===========
|
||||
|
||||
#sidebar `ControlCommandsSidebar <ControlCommandsSidebar.html>`_
|
||||
SAVE
|
||||
~~~~
|
||||
|
||||
Save the whole dataset on disk (this means that all the databases
|
||||
are saved, as well as keys with an EXPIRE set (the expire is
|
||||
preserved). The server hangs while the saving is notcompleted, no
|
||||
connection is served in the meanwhile. An OK codeis returned when
|
||||
the DB was fully stored in disk.
|
||||
|
||||
The background variant of this command is
|
||||
`BGSAVE <BgsaveCommand.html>`_ that is able to perform the saving
|
||||
in the background while the server continues serving other
|
||||
clients.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Status code reply <ReplyTypes.html>`_
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,24 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**ScardCommand: Contents**
|
||||
`SCARD \_key\_ <#SCARD%20_key_>`_
|
||||
`Return value <#Return%20value>`_
|
||||
ScardCommand
|
||||
============
|
||||
|
||||
#sidebar `SetCommandsSidebar <SetCommandsSidebar.html>`_
|
||||
SCARD \_key\_
|
||||
=============
|
||||
|
||||
*Time complexity O(1)*
|
||||
Return the set cardinality (number of elements). If the *key* does
|
||||
notexist 0 is returned, like for empty sets.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Integer reply <ReplyTypes.html>`_, specifically:
|
||||
::
|
||||
|
||||
the cardinality (number of elements) of the set as an integer.
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,30 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**SdiffCommand: Contents**
|
||||
`SDIFF \_key1\_ \_key2\_ ... \_keyN\_ <#SDIFF%20_key1_%20_key2_%20...%20_keyN_>`_
|
||||
`Return value <#Return%20value>`_
|
||||
SdiffCommand
|
||||
============
|
||||
|
||||
#sidebar `SetCommandsSidebar <SetCommandsSidebar.html>`_
|
||||
SDIFF \_key1\_ \_key2\_ ... \_keyN\_
|
||||
====================================
|
||||
|
||||
*Time complexity O(N) with N being the total number of elements of all the sets*
|
||||
Return the members of a set resulting from the difference between
|
||||
the firstset provided and all the successive sets. Example:
|
||||
|
||||
::
|
||||
|
||||
key1 = x,a,b,c
|
||||
key2 = c
|
||||
key3 = a,d
|
||||
SDIFF key1,key2,key3 => x,b
|
||||
|
||||
Non existing keys are considered like empty sets.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Multi bulk reply <ReplyTypes.html>`_, specifically the list of
|
||||
common elements.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,20 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**SdiffstoreCommand: Contents**
|
||||
`SDIFFSTORE \_dstkey\_ \_key1\_ \_key2\_ ... \_keyN\_ <#SDIFFSTORE%20_dstkey_%20_key1_%20_key2_%20...%20_keyN_>`_
|
||||
`Return value <#Return%20value>`_
|
||||
SdiffstoreCommand
|
||||
=================
|
||||
|
||||
#sidebar `SetCommandsSidebar <SetCommandsSidebar.html>`_
|
||||
SDIFFSTORE \_dstkey\_ \_key1\_ \_key2\_ ... \_keyN\_
|
||||
====================================================
|
||||
|
||||
*Time complexity O(N) where N is the total number of elements in all the provided sets*
|
||||
This command works exactly like SDIFF but instead of being returned
|
||||
the resulting set is stored in *dstkey*.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Status code reply <ReplyTypes.html>`_
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,20 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**SelectCommand: Contents**
|
||||
`SELECT \_index\_ <#SELECT%20_index_>`_
|
||||
`Return value <#Return%20value>`_
|
||||
SelectCommand
|
||||
=============
|
||||
|
||||
#sidebar `GenericCommandsSidebar <GenericCommandsSidebar.html>`_
|
||||
SELECT \_index\_
|
||||
================
|
||||
|
||||
Select the DB with having the specified zero-based numeric
|
||||
index.For default every new client connection is automatically
|
||||
selectedto DB 0.
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Status code reply <ReplyTypes.html>`_
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,20 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**SetCommand: Contents**
|
||||
`SET \_key\_ \_value\_ <#SET%20_key_%20_value_>`_
|
||||
`Return value <#Return%20value>`_
|
||||
SetCommand
|
||||
==========
|
||||
|
||||
#sidebar `StringCommandsSidebar <StringCommandsSidebar.html>`_
|
||||
SET \_key\_ \_value\_
|
||||
=====================
|
||||
|
||||
*Time complexity: O(1)*
|
||||
Set the string *value* as value of the *key*.The string can't be
|
||||
longer than 1073741824 bytes (1 GB).
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Status code reply <ReplyTypes.html>`_
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,24 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**SetCommandsSidebar: Contents**
|
||||
SetCommandsSidebar
|
||||
==================
|
||||
|
||||
== Set Commands ==
|
||||
|
||||
- `SADD <SaddCommand.html>`_
|
||||
- `SREM <SremCommand.html>`_
|
||||
- `SPOP <SpopCommand.html>`_
|
||||
- `SMOVE <SmoveCommand.html>`_
|
||||
- `SCARD <ScardCommand.html>`_
|
||||
- `SISMEMBER <SismemberCommand.html>`_
|
||||
- `SINTER <SinterCommand.html>`_
|
||||
- `SINTERSTORE <SinterstoreCommand.html>`_
|
||||
- `SUNION <SunionCommand.html>`_
|
||||
- `SUNIONSTORE <SunionstoreCommand.html>`_
|
||||
- `SDIFF <SdiffCommand.html>`_
|
||||
- `SDIFFSTORE <SdiffstoreCommand.html>`_
|
||||
- `SMEMBERS <SmembersCommand.html>`_
|
||||
- `SRANDMEMBER <SrandmemberCommand.html>`_
|
||||
- `SORT <SortCommand.html>`_
|
||||
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
@@ -0,0 +1,36 @@
|
||||
`|Redis Documentation| <index.html>`_
|
||||
**SetbitCommand: Contents**
|
||||
`SETBIT \_key\_ \_offset\_ \_value\_ (Redis > <#SETBIT%20_key_%20_offset_%20_value_%20(Redis%20%3E>`_
|
||||
`Return value <#Return%20value>`_
|
||||
SetbitCommand
|
||||
=============
|
||||
|
||||
SETBIT \_key\_ \_offset\_ \_value\_ (Redis >
|
||||
============================================
|
||||
|
||||
2.1.8) = *Time complexity: O(1)*
|
||||
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 is limited to
|
||||
2\ :sup:`32-1 (which 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`\ 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`\ 30-1
|
||||
(128MB allocation) takes ~80ms, setting bit number
|
||||
2\ :sup:`28-1 (32MB allocation) takes ~30ms and setting bit number 2`\ 26-1
|
||||
(8MB allocation) takes ~8ms. Note that once this first allocation
|
||||
is done, subsequent calls to SETBIT for the same *key* will not
|
||||
have the allocation overhead.
|
||||
Return value
|
||||
------------
|
||||
|
||||
`Integer reply <ReplyTypes.html>`_, specifically: the original bit
|
||||
value stored at *offset*.
|
||||
.. |Redis Documentation| image:: redis.png
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user