Commit 02d71527 authored by antirez's avatar antirez
Browse files

no more html documentation

parent 112569d1
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<link type="text/css" rel="stylesheet" href="style.css" />
</head>
<body>
<div id="page">
<div id='header'>
<a href="index.html">
<img style="border:none" alt="Redis Documentation" src="redis.png">
</a>
</div>
<div id="pagecontent">
<div class="index">
<!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
<b>StringCommandsSidebar: Contents</b>
</div>
<h1 class="wikiname">StringCommandsSidebar</h1>
<div class="summary">
</div>
<div class="narrow">
&iuml;&raquo;&iquest;== String Commands ==<br/><br/><ul><li> <a href="SetCommand.html">SET</a></li><li> <a href="GetCommand.html">GET</a></li><li> <a href="StrlenCommand.html">STRLEN</a></li><li> <a href="GetsetCommand.html">GETSET</a></li><li> <a href="SetnxCommand.html">SETNX</a></li><li> <a href="SetexCommand.html">SETEX</a></li><li> <a href="SetbitCommand.html">SETBIT</a></li><li> <a href="GetbitCommand.html">GETBIT</a></li><li> <a href="MsetCommand.html">MSET</a></li><li> <a href="MsetCommand.html">MSETNX</a></li><li> <a href="MgetCommand.html">MGET</a></li><li> <a href="IncrCommand.html">INCR</a></li><li> <a href="IncrCommand.html">INCRBY</a></li><li> <a href="IncrCommand.html">DECR</a></li><li> <a href="IncrCommand.html">DECRBY</a></li><li> <a href="AppendCommand.html">APPEND</a></li><li> <a href="SetrangeCommand.html">SETRANGE</a></li><li> <a href="SubstrCommand.html">GETRANGE (or SUBSTR)</a></li></ul>
</div>
</div>
</div>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<link type="text/css" rel="stylesheet" href="style.css" />
</head>
<body>
<div id="page">
<div id='header'>
<a href="index.html">
<img style="border:none" alt="Redis Documentation" src="redis.png">
</a>
</div>
<div id="pagecontent">
<div class="index">
<!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
<b>Strings: Contents</b><br>&nbsp;&nbsp;<a href="#Redis String Type">Redis String Type</a><br>&nbsp;&nbsp;<a href="#Implementation details">Implementation details</a>
</div>
<h1 class="wikiname">Strings</h1>
<div class="summary">
</div>
<div class="narrow">
&iuml;&raquo;&iquest;#sidebar <a href="StringCommandsSidebar.html">StringCommandsSidebar</a><h1><a name="Redis String Type">Redis String Type</a></h1>Strings are the most basic Redis kind of values. Redis Strings are binary safe, this means a Redis string can contain any kind of data, for instance a JPEG image or a serialized Ruby object, and so forth.<br/><br/>A String value can be at max 512 Megabytes in length.<br/><br/>Strings are treated as integer values by the <a href="IncrCommand.html">INCR</a> commands family, in this respect the value of an intger is limited to a singed 64 bit value.<br/><br/>Note that the single elements contained in Redis <a href="Lists.html">Lists</a>, <a href="Sets.html">Sets</a> and <a href="SortedSets.html">Sorted Sets</a>, are Redis Strings.<h1><a name="Implementation details">Implementation details</a></h1>Strings are implemented using a dynamic strings library called <code name="code" class="python">sds.c</code> (simple dynamic strings). This library caches the current length of the string, so to obtain the length of a Redis string is an O(1) operation (but currently there is no such STRLEN command. It will likely be added later).<br/><br/>Redis strings are incapsualted into Redis Objects. Redis Objects use a reference counting memory management system, so a single Redis String can be shared in different places of the dataset. This means that if you happen to use the same strings many times (especially if you have <i>object sharing</i> turned on in the configuration file) Redis will try to use the same string object instead to allocate one new every time.<br/><br/>Starting from version 1.1 Redis is also able to encode in a special way strings that are actually just numbers. Instead to save the string as an array of characters Redis will save the integer value in order to use less memory. With many datasets this can reduce the memory usage of about 30% compared to Redis 1.0.
</div>
</div>
</div>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<link type="text/css" rel="stylesheet" href="style.css" />
</head>
<body>
<div id="page">
<div id='header'>
<a href="index.html">
<img style="border:none" alt="Redis Documentation" src="redis.png">
</a>
</div>
<div id="pagecontent">
<div class="index">
<!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
<b>StrlenCommand: Contents</b><br>&nbsp;&nbsp;<a href="#STRLEN _key_ (Redis &gt;">STRLEN _key_ (Redis &gt;</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Return value">Return value</a>
</div>
<h1 class="wikiname">StrlenCommand</h1>
<div class="summary">
</div>
<div class="narrow">
&iuml;&raquo;&iquest;#sidebar <a href="StringCommandsSidebar.html">StringCommandsSidebar</a><h1><a name="STRLEN _key_ (Redis &gt;">STRLEN _key_ (Redis &gt;</a></h1> 2.1.8) =
<i>Time complexity: O(1)</i><blockquote>Returns the length of the string stored at the specified <i>key</i>.</blockquote>
<h2><a name="Return value">Return value</a></h2><a href="ReplyTypes.html">Integer reply</a>, specifically: the length of the string.
</div>
</div>
</div>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<link type="text/css" rel="stylesheet" href="style.css" />
</head>
<body>
<div id="page">
<div id='header'>
<a href="index.html">
<img style="border:none" alt="Redis Documentation" src="redis.png">
</a>
</div>
<div id="pagecontent">
<div class="index">
<!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
<b>SubstrCommand: Contents</b><br>&nbsp;&nbsp;<a href="#SUBSTR _key_ _start_ _end_">SUBSTR _key_ _start_ _end_</a><br>&nbsp;&nbsp;<a href="#GETRANGE _key_ _start_ _end_">GETRANGE _key_ _start_ _end_</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Return value">Return value</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Examples">Examples</a>
</div>
<h1 class="wikiname">SubstrCommand</h1>
<div class="summary">
</div>
<div class="narrow">
&iuml;&raquo;&iquest;#sidebar <a href="StringCommandsSidebar.html">StringCommandsSidebar</a><h1><a name="SUBSTR _key_ _start_ _end_">SUBSTR _key_ _start_ _end_</a></h1>
<h1><a name="GETRANGE _key_ _start_ _end_">GETRANGE _key_ _start_ _end_</a></h1>
<i>Time complexity: O(start+n) (with start being the start index and n the total length of the requested range). Note that the lookup part of this command is O(1) so for small strings this is actually an O(1) command.</i><b>Warning:</b> this command was renamed into GETRANGE. SUBSTR will be taken as an alias until the next major release of Redis.<br/><br/><blockquote>Return a subset of the string from offset <i>start</i> to offset <i>end</i>(both offsets are inclusive).Negative offsets can be used in order to provide an offset starting fromthe end of the string. So -1 means the last char, -2 the penultimate andso forth.</blockquote>
<blockquote>The function handles out of range requests without raising an error, butjust limiting the resulting range to the actual length of the string.</blockquote>
<h2><a name="Return value">Return value</a></h2><a href="ReplyTypes.html">Bulk reply</a><h2><a name="Examples">Examples</a></h2><pre class="codeblock python" name="code">
redis&gt; set s &quot;This is a string&quot;
OK
redis&gt; substr s 0 3
&quot;This&quot;
redis&gt; substr s -3 -1
&quot;ing&quot;
redis&gt; substr s 0 -1
&quot;This is a string&quot;
redis&gt; substr s 9 100000
&quot; string&quot;
</pre>
</div>
</div>
</div>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<link type="text/css" rel="stylesheet" href="style.css" />
</head>
<body>
<div id="page">
<div id='header'>
<a href="index.html">
<img style="border:none" alt="Redis Documentation" src="redis.png">
</a>
</div>
<div id="pagecontent">
<div class="index">
<!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
<b>SunionCommand: Contents</b><br>&nbsp;&nbsp;<a href="#SUNION _key1_ _key2_ ... _keyN_">SUNION _key1_ _key2_ ... _keyN_</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Return value">Return value</a>
</div>
<h1 class="wikiname">SunionCommand</h1>
<div class="summary">
</div>
<div class="narrow">
&iuml;&raquo;&iquest;#sidebar <a href="SetCommandsSidebar.html">SetCommandsSidebar</a><h1><a name="SUNION _key1_ _key2_ ... _keyN_">SUNION _key1_ _key2_ ... _keyN_</a></h1>
<i>Time complexity O(N) where N is the total number of elements in all the provided sets</i><blockquote>Return the members of a set resulting from the union of all thesets hold at the specified keys. Like in LRANGE the result is sent tothe client as a multi-bulk reply (see the protocol specification formore information). If just a single key is specified, then this commandproduces the same result as <a href="SmembersCommand.html">SMEMBERS</a>.</blockquote>
<blockquote>Non existing keys are considered like empty sets.</blockquote>
<h2><a name="Return value">Return value</a></h2><a href="ReplyTypes.html">Multi bulk reply</a>, specifically the list of common elements.
</div>
</div>
</div>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<link type="text/css" rel="stylesheet" href="style.css" />
</head>
<body>
<div id="page">
<div id='header'>
<a href="index.html">
<img style="border:none" alt="Redis Documentation" src="redis.png">
</a>
</div>
<div id="pagecontent">
<div class="index">
<!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
<b>SunionstoreCommand: Contents</b><br>&nbsp;&nbsp;<a href="#SUNIONSTORE _dstkey_ _key1_ _key2_ ... _keyN_">SUNIONSTORE _dstkey_ _key1_ _key2_ ... _keyN_</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Return value">Return value</a>
</div>
<h1 class="wikiname">SunionstoreCommand</h1>
<div class="summary">
</div>
<div class="narrow">
&iuml;&raquo;&iquest;#sidebar <a href="SetCommandsSidebar.html">SetCommandsSidebar</a><h1><a name="SUNIONSTORE _dstkey_ _key1_ _key2_ ... _keyN_">SUNIONSTORE _dstkey_ _key1_ _key2_ ... _keyN_</a></h1>
<i>Time complexity O(N) where N is the total number of elements in all the provided sets</i><blockquote>This command works exactly like SUNION but instead of being returned the resulting set is stored as <i>dstkey</i>. Any existing value in <i>dstkey</i> will be over-written.</blockquote>
<h2><a name="Return value">Return value</a></h2><a href="ReplyTypes.html">Status code reply</a>
</div>
</div>
</div>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<link type="text/css" rel="stylesheet" href="style.css" />
</head>
<body>
<div id="page">
<div id='header'>
<a href="index.html">
<img style="border:none" alt="Redis Documentation" src="redis.png">
</a>
</div>
<div id="pagecontent">
<div class="index">
<!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
<b>SupportedLanguages: Contents</b><br>&nbsp;&nbsp;<a href="#Supported Languages (DRAFT)">Supported Languages (DRAFT)</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#TODO">TODO</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Features Support Matrix">Features Support Matrix</a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Version 1.1">Version 1.1</a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Version 1.0">Version 1.0</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Client Libraries Reference">Client Libraries Reference</a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#as3 (ActionScript 3)">as3 (ActionScript 3)</a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#redis-clojure (Clojure)">redis-clojure (Clojure)</a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#CL-Redis (Common Lisp)">CL-Redis (Common Lisp)</a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#erldis (Erlang)">erldis (Erlang)</a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Go-Redis (Go)">Go-Redis (Go)</a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#haskell-redis (Haskell)">haskell-redis (Haskell)</a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Java">Java</a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#redis-lua (Lua)">redis-lua (Lua)</a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Perl">Perl</a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#PHP">PHP</a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Python">Python</a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#txredis">txredis</a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#redis-rb (Ruby)">redis-rb (Ruby)</a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#scala-redis (Scala)">scala-redis (Scala)</a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Tcl">Tcl</a>
</div>
<h1 class="wikiname">SupportedLanguages</h1>
<div class="summary">
</div>
<div class="narrow">
<h1><a name="Supported Languages (DRAFT)">Supported Languages (DRAFT)</a></h1>Wondering if you can use Redis from your favorite language? Well here is the definitive guide to the available client libraries.<br/><br/>This libraries are intended to expose Redis commands, but you also have the option to use some higher level libraries that provide a <b><a href="ObjectHashMappers.html">Object Hash Mappings</a></b> pretty much the same idea implemented by a classic <b>ORM</b>.<h2><a name="TODO">TODO</a></h2><ul><li> Add <a href="http://github.com/madsimian/em-redis" target="_blank">http://github.com/madsimian/em-redis</a></li><li> Add <a href="http://github.com/besquared/redis-datastructures" target="_blank">http://github.com/besquared/redis-datastructures</a></li><li> Add <a href="http://github.com/sma/redis-node-client" target="_blank">http://github.com/sma/redis-node-client</a></li></ul>
<h2><a name="Features Support Matrix">Features Support Matrix</a></h2> <br/><br/>The following matrix should give you a quick overviwe of the state of the different client libraries existing for each supported language.<br/><br/>The core command set is the one of Version 1.0, while <a href="Sharding.html">Sharding</a> and <a href="Pipelining.html">Pipelining</a> are convenient client side features not tied to any Redis server version.<h3><a name="Version 1.1">Version 1.1</a></h3>Compatible client libraries are expected to implement the command sets specified in <b>Version 1.0</b> plus:<br/><br/><ul><li> <b>String</b>: MSET, MSETNX.</li><li> <b>List</b>: RPOPLPUSH.</li><li> <b>Sorted Set (ZSET)</b>: ZADD, ZREM, ZRANGE, ZREVRANGE, ZRANGEBYSCORE, ZCARD, ZSCORE.</li></ul>
<h3><a name="Version 1.0">Version 1.0</a></h3> <br/><br/>Compatible client libraries are expected to implement the following command sets:<br/><br/><ul><li> <b>String</b>: GET, SET, SETNX, DEL, EXISTS, INCR, DECR, MGET, INCRBY, DECRBY, GETSET, TYPE.</li><li> <b>List</b>: RPUSH, LPUSH, RPOP, LPOP, LLEN, LINDEX, LSET, LRANGE, LTRIM, LREM.</li><li> <b>Set</b>: SADD, SREM, SMOVE, SISMEMBER, SCARD, SPOP, SINTER, SINTERSTORE, SUNION, SUNIONSTORE, SDIFF, SDIFFSTORE, SMEMBERS.</li><li> <b>Keyspace</b>: KEYS, RANDOMKEY, RENAME, RENAMENX, DBSIZE, EXPIRE, TTL.</li><li> <b>Databases</b>: SELECT, MOVE, FLUSHDB, FLUSHALL.</li><li> <b>Sort</b>: SORT</li><li> <b>Connection</b>: AUTH, QUIT?. ???</li><li> <b>Persistence</b>: SAVE, BGSAVE, LASTSAVE, SHUTDOWN?. ???</li><li> <b>Server</b>: INFO, MONITOR? SLAVEOF? ???</li></ul><blockquote></blockquote><table><tr><td style="border: 1px solid #aaa; padding: 5px;"> <b>Language</b> </td><td style="border: 1px solid #aaa; padding: 5px;"> <b>Name</b> </td><td style="border: 1px solid #aaa; padding: 5px;"> <b>Sharding</b> </td><td style="border: 1px solid #aaa; padding: 5px;"> <b>Pipelining</b> </td><td style="border: 1px solid #aaa; padding: 5px;"> <b>1.1</b> </td><td style="border: 1px solid #aaa; padding: 5px;"> <b>1.0</b> </td></tr><tr><td style="border: 1px solid #aaa; padding: 5px;"> ActionScript 3</td><td style="border: 1px solid #aaa; padding: 5px;"> as3redis </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td></tr><tr><td style="border: 1px solid #aaa; padding: 5px;"> Clojure </td><td style="border: 1px solid #aaa; padding: 5px;"> redis-clojure </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> Partial </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td></tr><tr><td style="border: 1px solid #aaa; padding: 5px;"> Common Lisp </td><td style="border: 1px solid #aaa; padding: 5px;"> CL-Redis </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td></tr><tr><td style="border: 1px solid #aaa; padding: 5px;"> Erlang </td><td style="border: 1px solid #aaa; padding: 5px;"> erldis </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> Looks like </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> Looks like </td></tr><tr><td style="border: 1px solid #aaa; padding: 5px;"> Go </td><td style="border: 1px solid #aaa; padding: 5px;"> Go-Redis </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td></tr><tr><td style="border: 1px solid #aaa; padding: 5px;"> Haskell </td><td style="border: 1px solid #aaa; padding: 5px;"> haskell-redis </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td></tr><tr><td style="border: 1px solid #aaa; padding: 5px;"> Java </td><td style="border: 1px solid #aaa; padding: 5px;"> JDBC-Redis </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td></tr><tr><td style="border: 1px solid #aaa; padding: 5px;"> Java </td><td style="border: 1px solid #aaa; padding: 5px;"> JRedis </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td></tr><tr><td style="border: 1px solid #aaa; padding: 5px;"> Java </td><td style="border: 1px solid #aaa; padding: 5px;"> Jedis </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td></tr><tr><td style="border: 1px solid #aaa; padding: 5px;"> LUA </td><td style="border: 1px solid #aaa; padding: 5px;"> redis-lua </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td></tr><tr><td style="border: 1px solid #aaa; padding: 5px;"> Perl </td><td style="border: 1px solid #aaa; padding: 5px;"> Redis Client </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td></tr><tr><td style="border: 1px solid #aaa; padding: 5px;"> Perl </td><td style="border: 1px solid #aaa; padding: 5px;"> AnyEvent::Redis </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td></tr><tr><td style="border: 1px solid #aaa; padding: 5px;"> PHP </td><td style="border: 1px solid #aaa; padding: 5px;"> Redis PHP Bindings </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td></tr><tr><td style="border: 1px solid #aaa; padding: 5px;"> PHP </td><td style="border: 1px solid #aaa; padding: 5px;"> phpredis (C) </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td></tr><tr><td style="border: 1px solid #aaa; padding: 5px;"> PHP </td><td style="border: 1px solid #aaa; padding: 5px;"> Predis </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td></tr><tr><td style="border: 1px solid #aaa; padding: 5px;"> PHP </td><td style="border: 1px solid #aaa; padding: 5px;"> Redisent </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td></tr><tr><td style="border: 1px solid #aaa; padding: 5px;"> Python </td><td style="border: 1px solid #aaa; padding: 5px;"> Python Client </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td></tr><tr><td style="border: 1px solid #aaa; padding: 5px;"> Python </td><td style="border: 1px solid #aaa; padding: 5px;"> py-redis </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> Partial </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td></tr><tr><td style="border: 1px solid #aaa; padding: 5px;"> Python </td><td style="border: 1px solid #aaa; padding: 5px;"> txredis </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td></tr><tr><td style="border: 1px solid #aaa; padding: 5px;"> Ruby </td><td style="border: 1px solid #aaa; padding: 5px;"> redis-rb </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td></tr><tr><td style="border: 1px solid #aaa; padding: 5px;"> Scala </td><td style="border: 1px solid #aaa; padding: 5px;"> scala-redis </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td></tr><tr><td style="border: 1px solid #aaa; padding: 5px;"> TCL </td><td style="border: 1px solid #aaa; padding: 5px;"> TCL </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> No </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td><td style="border: 1px solid #aaa; padding: 5px;"> Yes </td></tr></table>
<h2><a name="Client Libraries Reference">Client Libraries Reference</a></h2><h3><a name="as3 (ActionScript 3)">as3 (ActionScript 3)</a></h3><ul><li> An ActionScript 3 (Flash) library for Redis.</li><li> Repository: <a href="http://github.com/claus/as3redis" target="_blank">http://github.com/claus/as3redis</a></li><li> Author: Claus Wahlers, <a href="http://twitter.com/cwahlers" target="_blank"> @cwahlers</a>.</li></ul>
<h3><a name="redis-clojure (Clojure)">redis-clojure (Clojure)</a></h3><ul><li> A Clojure client library for the key-value storage system Redis.</li><li> Repository: <a href="http://github.com/ragnard/redis-clojure" target="_blank">http://github.com/ragnard/redis-clojure</a></li><li> Author: Ragnar Dahl&Atilde;&copy;n, <a href="http://twitter.com/ragge" target="_blank">@ragge</a>.</li></ul>
<h3><a name="CL-Redis (Common Lisp)">CL-Redis (Common Lisp)</a></h3><ul><li> Common Lisp client library for Redis, an advanced key/value store.</li><li> Home Page: <a href="http://www.cliki.net/cl-redis" target="_blank">http://www.cliki.net/cl-redis</a></li><li> Author: Mahmud, <a href="http://twitter.com/BigThingist" target="_blank">@BigThingist</a>.</li></ul>
<h3><a name="erldis (Erlang)">erldis (Erlang)</a></h3><ul><li> Client protocol for redis key-value store.</li><li> Author: <a href="http://www.adroll.com/" target="_blank">Valentino Volonghi</a>, <a href="http://twitter.com/dialtone_" target="_blank">@dialtone_</a>.</li><li> Repository: <a href="http://bitbucket.org/adroll/erldis/" target="_blank">http://bitbucket.org/adroll/erldis/</a></li></ul>
<h3><a name="Go-Redis (Go)">Go-Redis (Go)</a></h3><ul><li> Client protocol for redis key-value store.</li><li> Author: Joubin Houshyar, <a href="http://twitter.com/SunOf27" target="_blank">@SunOf27</a>.</li><li> Repository: <a href="http://github.com/alphazero/Go-Redis" target="_blank">http://github.com/alphazero/Go-Redis</a></li></ul>
<h3><a name="haskell-redis (Haskell)">haskell-redis (Haskell)</a></h3><ul><li> A Haskell binding for the Redis database.</li><li> Author: <a href="http://obvioushints.blogspot.com/" target="_blank">Alvaro Videla</a>, <a href="http://twitter.com/old_sound" target="_blank">@old_sound</a>.</li><li> Repository: <a href="http://bitbucket.org/videlalvaro/redis-haskell/wiki/Home" target="_blank"> </a></li></ul>
<h3><a name="Java">Java</a></h3><h4><a name="JDBC-Redis">JDBC-Redis</a></h4><ul><li> JDBC-Redis is Java driver using the JDBC interface for Redis Database. This project doesn't aim for a complete implementation of the JDBC specification since Redis isn't a relational database, but should provide a familiar interface to Java developers interact with Redis.</li><li> Repository: <a href="http://code.google.com/p/jdbc-redis/" target="_blank">http://code.google.com/p/jdbc-redis/</a></li></ul>
<h4><a name="JRedis">JRedis</a></h4><ul><li> Java Client and Connectors for Redis JCA compliant. Currently offers a complete functioning Synchronous connector, Asynchronous connection and pipelining support under heavy development.</li><li> Author: Joubin Houshyar, <a href="http://twitter.com/SunOf27" target="_blank">@SunOf27</a>.</li><li> Home: <a href="http://code.google.com/p/jredis/" target="_blank">http://code.google.com/p/jredis/</a></li><li> Repository: <a href="http://github.com/alphazero/jredis" target="_blank">http://github.com/alphazero/jredis</a></li></ul>
<h4><a name="Jedis">Jedis</a></h4><ul><li> Jedis is a small and sane Redis client for Java. It aims to be easier to use by providing a more natural API. It currently supports the binary-safe protocol and pipelining. Sharding and connection pooling is on the way.</li><li> Author: Jonathan Leibiusky, <a href="http://twitter.com/xetorthio" target="_blank">@xetorthio</a>.</li><li> Repository: <a href="http://github.com/xetorthio/jedis" target="_blank">http://github.com/xetorthio/jedis</a></li></ul>
<h3><a name="redis-lua (Lua)">redis-lua (Lua)</a></h3><ul><li> A Lua client library for the redis key value storage system.</li><li> Author: <a href="http://www.clorophilla.net/blog/" target="_blank">Daniele Alessandri</a>, <a href="http://twitter.com/jol1hahn" target="_blank">@jol1hahn</a>.</li><li> Repository: <a href="http://github.com/nrk/redis-lua" target="_blank">http://github.com/nrk/redis-lua</a></li></ul>
<h3><a name="Perl">Perl</a></h3><h4><a name="Perl Client">Perl Client</a></h4><ul><li> Perl binding for Redis database.</li><li> Author: <a href="http://blog.rot13.org/" target="_blank">Dobrica Pavlinusic</a>, <a href="http://twitter.com/dpavlin" target="_blank">@dpavlin</a>.</li><li> Repository: <a href="http://svn.rot13.org/index.cgi/Redis" target="_blank">http://svn.rot13.org/index.cgi/Redis</a></li></ul>
<h4><a name="AnyEvent::Redis">AnyEvent::Redis</a></h4><ul><li> Non-blocking Redis client.</li><li> Author: <a href="http://bulknews.typepad.com/" target="_blank">Tatsuhiko Miyagawa</a>, <a href="http://twitter.com/miyagawa" target="_blank">@miyagawa</a>.</li><li> Repository: <a href="http://github.com/miyagawa/AnyEvent-Redis/" target="_blank">http://github.com/miyagawa/AnyEvent-Redis/</a></li></ul>
<h3><a name="PHP">PHP</a></h3><h4><a name="Redis PHP Bindings">Redis PHP Bindings</a></h4><ul><li> Simple default binding in Redis main repository. No longer under active development.</li><li> Author: <a href="http://qix.it/" target="_blank">Ludovico Magnocavallo</a>, <a href="http://twitter.com/ludo" target="_blank">@ludo</a>.</li><li> Repository: <a href="http://code.google.com/p/redis/source/browse/#svn/trunk/client-libraries/php" target="_blank">http://code.google.com/p/redis/source/browse/#svn/trunk/client-libraries/php</a></li></ul>
<h4><a name="phpredis">phpredis</a></h4><ul><li> This extension provides an API for communicating with Redis database, a persistent key-value database with built-in net interface written in ANSI-C for Posix systems.</li><li> Author: <a href="http://www.alfonsojimenez.com/" target="_blank">Alfonso Jimenez</a> , (<a href="http://twitter.com/alfonsojimenez" target="_blank">@alfonsojimenez</a>), Nicolas Favre-F&Atilde;&copy;lix and Nasreddine Bouafif.</li><li> Repository: <a href="http://github.com/owlient/phpredis" target="_blank">http://github.com/owlient/phpredis</a></li></ul>
<h4><a name="Predis">Predis</a></h4><ul><li> A flexible and feature-complete PHP client library for the Redis key-value database. Predis is currently a work-in-progress and it targets PHP &gt;= 5.3, though it is highly due to be backported to PHP &gt;= 5.2.6 as soon as the public API and the internal design on the main branch will be considered stable enough.</li><li> Author: <a href="http://www.clorophilla.net/blog/" target="_blank">Daniele Alessandri</a>, <a href="http://twitter.com/jol1hahn" target="_blank">@jol1hahn</a></li><li> Repository: <a href="http://github.com/nrk/predis/" target="_blank">http://github.com/nrk/predis/</a></li></ul>
<h4><a name="Redisent">Redisent</a></h4><ul><li> Redisent is a simple, no-nonsense interface to the Redis key-value store for modest developers. Due to the way it is implemented, it is flexible and tolerant of changes to the Redis protocol.</li><li> Author: <a href="http://blog.justinpoliey.com/" target="_blank">Justin Poliey</a>, <a href="http://twitter.com/justinpoliey" target="_blank">@justinpoliey</a></li><li> Repository: <a href="http://github.com/jdp/redisent" target="_blank">http://github.com/jdp/redisent</a></li></ul>
<h3><a name="Python">Python</a></h3><h4><a name="Python Client">Python Client</a></h4><ul><li> Simple Python client in Redis main repository. No longer under active development.</li><li> Author: <a href="http://qix.it/" target="_blank">Ludovico Magnocavallo</a>, <a href="http://twitter.com/ludo" target="_blank">@ludo</a>.</li><li> Repository: <a href="http://code.google.com/p/redis/source/browse/#svn/trunk/client-libraries/python" target="_blank">http://code.google.com/p/redis/source/browse/#svn/trunk/client-libraries/python</a></li></ul>
<h4><a name="py-redis">py-redis</a></h4><ul><li> Redis Python Client.</li><li> Author: <a href="Andy.html">McCurdy</a>, <a href="http://twitter.com/andymccurdy" target="_blank">@andymccurdy</a>.</li><li> Repository: <a href="http://github.com/andymccurdy/redis-py" target="_blank">http://github.com/andymccurdy/redis-py</a></li></ul>
<h3><a name="txredis">txredis</a></h3><ul><li> Python/Twisted client for Redis key-value store</li><li> Author: Dorian Raymer, <a href="http://twitter.com/dio_rian" target="_blank">@dio_rian</a>.</li><li> PyPI: <a href="http://pypi.python.org/pypi/txredis/0.1.1" target="_blank">http://pypi.python.org/pypi/txredis/0.1.1</a></li></ul>
<h3><a name="redis-rb (Ruby)">redis-rb (Ruby)</a></h3><ul><li> A Ruby client library for the redis key value storage engine.</li><li> Author: <a href="http://brainspl.at/" target="_blank">Ezra Zygmuntowicz</a>, <a href="http://twitter.com/ezmobius" target="_blank">@ezmobius</a>.</li><li> Repository: <a href="http://github.com/ezmobius/redis-rb" target="_blank">http://github.com/ezmobius/redis-rb</a></li></ul>
<h3><a name="scala-redis (Scala)">scala-redis (Scala)</a></h3><ul><li> A scala library for connecting to a redis server, or a cluster of redis nodes using consistent hashing on the client side.</li><li> Author: <a href="http://www.linkedin.com/in/alejandrocrosa" target="_blank">Alejandro Crosa</a>, <a href="http://twitter.com/alejandrocrosa" target="_blank">@alejandrocrosa</a>.</li><li> Repository: <a href="http://github.com/acrosa/scala-redis" target="_blank">http://github.com/acrosa/scala-redis</a></li></ul>
<h3><a name="Tcl">Tcl</a></h3><ul><li> The official version is included in the Redis tarball since it's maintained by Salvatore. </li><li> Author: <a href="http://invece.org/" target="_blank">Salvatore Sanfilippo</a>, <a href="http://twitter.com/antirez" target="_blank">@antirez</a></li><li> Repository: <a href="http://github.com/antirez/redis/blob/master/redis.tcl" target="_blank">http://github.com/antirez/redis/blob/master/redis.tcl</a></li></ul>
</div>
</div>
</div>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<link type="text/css" rel="stylesheet" href="style.css" />
</head>
<body>
<div id="page">
<div id='header'>
<a href="index.html">
<img style="border:none" alt="Redis Documentation" src="redis.png">
</a>
</div>
<div id="pagecontent">
<div class="index">
<!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
<b>SupportedPlatforms: Contents</b><br>&nbsp;&nbsp;<a href="#Supported Platforms">Supported Platforms</a>
</div>
<h1 class="wikiname">SupportedPlatforms</h1>
<div class="summary">
</div>
<div class="narrow">
<h1><a name="Supported Platforms">Supported Platforms</a></h1>Redis can be compiled in most POSIX systems, but the development targets mainly:<br/><br/><ul><li> Linux</li><li> Mac OS X</li><li> FreeBSD</li><li> OpenBSD</li><li> Solaris (startting with <a href="RoadMap.html">Version 1.1</a>)</li></ul>
Windows (using CygWin) is not a supported platform.
</div>
</div>
</div>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<link type="text/css" rel="stylesheet" href="style.css" />
</head>
<body>
<div id="page">
<div id='header'>
<a href="index.html">
<img style="border:none" alt="Redis Documentation" src="redis.png">
</a>
</div>
<div id="pagecontent">
<div class="index">
<!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
<b>TemplateCommand: Contents</b><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Return value">Return value</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#See also">See also</a>
</div>
<h1 class="wikiname">TemplateCommand</h1>
<div class="summary">
</div>
<div class="narrow">
&iuml;&raquo;&iquest;
<h2><a name="Return value">Return value</a></h2><a href="ReplyTypes.html">ReplyTypes</a><h2><a name="See also">See also</a></h2>
<ul><li> []</li></ul>
</div>
</div>
</div>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<link type="text/css" rel="stylesheet" href="style.css" />
</head>
<body>
<div id="page">
<div id='header'>
<a href="index.html">
<img style="border:none" alt="Redis Documentation" src="redis.png">
</a>
</div>
<div id="pagecontent">
<div class="index">
<!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
<b>TtlCommand: Contents</b><br>&nbsp;&nbsp;<a href="#TTL _key_">TTL _key_</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Return value">Return value</a>
</div>
<h1 class="wikiname">TtlCommand</h1>
<div class="summary">
</div>
<div class="narrow">
&iuml;&raquo;&iquest;#sidebar <a href="GenericCommandsSidebar.html">GenericCommandsSidebar</a><h1><a name="TTL _key_">TTL _key_</a></h1><blockquote>The TTL command returns the remaining time to live in seconds of a key that has an <a href="ExpireCommand.html">EXPIRE</a> set. This introspection capability allows a Redis client to check how many seconds a given key will continue to be part of the dataset. If the Key does not exists or does not have an associated expire, -1 is returned.</blockquote>
<h2><a name="Return value">Return value</a></h2><a href="ReplyTypes.html">Integer reply</a>
</div>
</div>
</div>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<link type="text/css" rel="stylesheet" href="style.css" />
</head>
<body>
<div id="page">
<div id='header'>
<a href="index.html">
<img style="border:none" alt="Redis Documentation" src="redis.png">
</a>
</div>
<div id="pagecontent">
<div class="index">
<!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
<b>TwitterAlikeExample: Contents</b><br>&nbsp;&nbsp;<a href="#A case study: Design and implementation of a simple Twitter clone using only the Redis key-value store as database and PHP">A case study: Design and implementation of a simple Twitter clone using only the Redis key-value store as database and PHP</a><br>&nbsp;&nbsp;<a href="#Key-value stores basics">Key-value stores basics</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Atomic operations">Atomic operations</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Beyond key-value stores">Beyond key-value stores</a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#The set data type">The set data type</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Prerequisites">Prerequisites</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Data layout">Data layout</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Following, followers and updates">Following, followers and updates</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Authentication">Authentication</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Updates">Updates</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Paginating updates">Paginating updates</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Following users">Following users</a><br>&nbsp;&nbsp;<a href="#Making it horizontally scalable">Making it horizontally scalable</a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Hashing the key">Hashing the key</a><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Special keys">Special keys</a>
</div>
<h1 class="wikiname">TwitterAlikeExample</h1>
<div class="summary">
</div>
<div class="narrow">
<h1><a name="A case study: Design and implementation of a simple Twitter clone using only the Redis key-value store as database and PHP">A case study: Design and implementation of a simple Twitter clone using only the Redis key-value store as database and PHP</a></h1>In this article I'll explain the design and the implementation of a <a href="http://retwis.antirez.com" target="_blank">simple clone of Twitter</a> written using PHP and <a href="http://code.google.com/p/redis/" target="_blank">Redis</a> as only database. The programming community uses to look at key-value stores like special databases that can't be used as drop in replacement for a relational database for the development of web applications. This article will try to prove the contrary.<br/><br/>Our Twitter clone, <a href="http://retwis.antirez.com" target="_blank">called Retwis</a>, is structurally simple, has very good performances, and can be distributed among N web servers and M Redis servers with very little efforts. You can find the source code <a href="http://code.google.com/p/redis/downloads/list" target="_blank">here</a>.<br/><br/>We use PHP for the example since it can be read by everybody. The same (or... much better) results can be obtained using Ruby, Python, Erlang, and so on.<br/><br/><b>News! <a href="http://retwisrb.danlucraft.com/" target="_blank">Retwis-rb</a> is a port of Retwis to Ruby and Sinatra written by Daniel Lucraft!</b> With full source code included of course, the git repository is linked at the end of the Retwis-RB page. The rest of this article targets PHP, but Ruby programmers can also check the other source code, it conceptually very similar.<h1><a name="Key-value stores basics">Key-value stores basics</a></h1>
The essence of a key-value store is the ability to store some data, called <i>value</i>, inside a key. This data can later be retrieved only if we know the exact key used to store it. There is no way to search something by value. So for example I can use the command SET to store the value <b>bar</b> at key <b>foo</b>:<br/><br/><pre class="codeblock python" name="code">
SET foo bar
</pre>Redis will store our data permanently, so we can later ask for &quot;<i>What is the value stored at key foo?</i>&quot; and Redis will reply with <b>bar</b>:<br/><br/><pre class="codeblock python python" name="code">
GET foo =&gt; bar
</pre>Other common operations provided by key-value stores are DEL used to delete a given key, and the associated value, SET-if-not-exists (called SETNX on Redis) that sets a key only if it does not already exist, and INCR that is able to atomically increment a number stored at a given key:<br/><br/><pre class="codeblock python python python" name="code">
SET foo 10
INCR foo =&gt; 11
INCR foo =&gt; 12
INCR foo =&gt; 13
</pre><h2><a name="Atomic operations">Atomic operations</a></h2>
So far it should be pretty simple, but there is something special about INCR. Think about this, why to provide such an operation if we can do it ourself with a bit of code? After all it is as simple as:<br/><br/><pre class="codeblock python python python python" name="code">
x = GET foo
x = x + 1
SET foo x
</pre>The problem is that doing the increment this way will work as long as there is only a client working with the value <i>x</i> at a time. See what happens if two computers are accessing this data at the same time:<br/><br/><pre class="codeblock python python python python python" name="code">
x = GET foo (yields 10)
y = GET foo (yields 10)
x = x + 1 (x is now 11)
y = y + 1 (y is now 11)
SET foo x (foo is now 11)
SET foo y (foo is now 11)
</pre>Something is wrong with that! We incremented the value two times, but instead to go from 10 to 12 our key holds 11. This is because the INCR operation done with <code name="code" class="python">GET / increment / SET</code> <b>is not an atomic operation</b>. Instead the INCR provided by Redis, Memcached, ..., are atomic implementations, the server will take care to protect the get-increment-set for all the time needed to complete in order to prevent simultaneous accesses.<br/><br/>What makes Redis different from other key-value stores is that it provides more operations similar to INCR that can be used together to model complex problems. This is why you can use Redis to write whole web applications without using an SQL database and without to get mad.
<h2><a name="Beyond key-value stores">Beyond key-value stores</a></h2>
In this section we will see what Redis features we need to build our Twitter clone. The first thing to know is that Redis values can be more than strings. Redis supports Lists and Sets as values, and there are atomic operations to operate against this more advanced values so we are safe even with multiple accesses against the same key. Let's start from Lists:<br/><br/><pre class="codeblock python python python python python python" name="code">
LPUSH mylist a (now mylist holds one element list 'a')
LPUSH mylist b (now mylist holds 'b,a')
LPUSH mylist c (now mylist holds 'c,b,a')
</pre>LPUSH means <i>Left Push</i>, that is, add an element to the left (or to the head) of the list stored at <i>mylist</i>. If the key <i>mylist</i> does not exist it is automatically created by Redis as an empty list before the PUSH operation. As you can imagine, there is also the RPUSH operation that adds the element on the right of the list (on the tail).<br/><br/>This is very useful for our Twitter clone. Updates of users can be stored into a list stored at <code name="code" class="python">username:updates</code> for instance. There are operations to get data or information from Lists of course. For instance LRANGE returns a range of the list, or the whole list.<br/><br/><pre class="codeblock python python python python python python python" name="code">
LRANGE mylist 0 1 =&gt; c,b
</pre>LRANGE uses zero-based indexes, that is the first element is 0, the second 1, and so on. The command aguments are <code name="code" class="python">LRANGE key first-index last-index</code>. The <i>last index</i> argument can be negative, with a special meaning: -1 is the last element of the list, -2 the penultimate, and so on. So in order to get the whole list we can use:<br/><br/><pre class="codeblock python python python python python python python python" name="code">
LRANGE mylist 0 -1 =&gt; c,b,a
</pre>Other important operations are LLEN that returns the length of the list, and LTRIM that is like LRANGE but instead of returning the specified range <b>trims</b> the list, so it is like <i>Get range from mylist, Set this range as new value</i> but atomic. We will use only this List operations, but make sure to check the <a href="http://code.google.com/p/redis/wiki/README" target="_blank">Redis documentation</a> to discover all the List operations supported by Redis.
<h3><a name="The set data type">The set data type</a></h3>
There is more than Lists, Redis also supports Sets, that are unsorted collection of elements. It is possible to add, remove, and test for existence of members, and perform intersection between different Sets. Of course it is possible to ask for the list or the number of elements of a Set. Some example will make it more clear. Keep in mind that SADD is the <i>add to set</i> operation, SREM is the <i>remove from set</i> operation, <i>sismember</i> is the <i>test if it is a member</i> operation, and SINTER is <i>perform intersection</i> operation. Other operations are SCARD that is used to get the cardinality (the number of elements) of a Set, and SMEMBERS that will return all the members of a Set.<br/><br/><pre class="codeblock python python python python python python python python python" name="code">
SADD myset a
SADD myset b
SADD myset foo
SADD myset bar
SCARD myset =&gt; 4
SMEMBERS myset =&gt; bar,a,foo,b
</pre>Note that SMEMBERS does not return the elements in the same order we added them, since Sets are <b>unsorted</b> collections of elements. When you want to store the order it is better to use Lists instead. Some more operations against Sets:<br/><br/><pre class="codeblock python python python python python python python python python python" name="code">
SADD mynewset b
SADD mynewset foo
SADD mynewset hello
SINTER myset mynewset =&gt; foo,b
</pre>SINTER can return the intersection between Sets but it is not limited to two sets, you may ask for intersection of 4,5 or 10000 Sets. Finally let's check how SISMEMBER works:<br/><br/><pre class="codeblock python python python python python python python python python python python" name="code">
SISMEMBER myset foo =&gt; 1
SISMEMBER myset notamember =&gt; 0
</pre>Ok I think we are ready to start coding!
<h2><a name="Prerequisites">Prerequisites</a></h2>
If you didn't download it already please <a href="http://code.google.com/p/redis/wiki/README" target="_blank">grab the source code of Retwis</a>. It's a simple tar.gz file with a few of .php files inside. The implementation is very simple. You will find the PHP library client inside (redis.php) that is used to talk with the Redis server from PHP. This library was written by <a href="http://qix.it" target="_blank">Ludovico Magnocavallo</a> and you are free to reuse this in your own projects, but for updated version of the library please download the Redis distribution.<br/><br/>Another thing you probably want is a working Redis server. Just get the source, compile with make, and run with ./redis-server and you are done. No configuration is required at all in order to play with it or to run Retwis in your computer.
<h2><a name="Data layout">Data layout</a></h2>
Working with a relational database this is the stage were the database layout should be produced in form of tables, indexes, and so on. We don't have tables, so what should be designed? We need to identify what keys are needed to represent our objects and what kind of values this keys need to hold.<br/><br/>Let's start from Users. We need to represent this users of course, with the username, userid, password, followers and following users, and so on. The first question is, what should identify an user inside our system? The username can be a good idea since it is unique, but it is also too big, and we want to stay low on memory. So like if our DB was a relational one we can associate an unique ID to every user. Every other reference to this user will be done by id. That's very simple to do, because we have our atomic INCR operation! When we create a new user we can do something like this, assuming the user is callled &quot;antirez&quot;:<br/><br/><pre class="codeblock python python python python python python python python python python python python" name="code">
INCR global:nextUserId =&gt; 1000
SET uid:1000:username antirez
SET uid:1000:password p1pp0
</pre>We use the <i>global:nextUserId</i> key in order to always get an unique ID for every new user. Then we use this unique ID to populate all the other keys holding our user data. <b>This is a Design Pattern</b> with key-values stores! Keep it in mind.
Besides the fields already defined, we need some more stuff in order to fully define an User. For example sometimes it can be useful to be able to get the user ID from the username, so we set this key too:<br/><br/><pre class="codeblock python python python python python python python python python python python python python" name="code">
SET username:antirez:uid 1000
</pre>This may appear strange at first, but remember that we are only able to access data by key! It's not possible to tell Redis to return the key that holds a specific value. This is also <b>our strength</b>, this new paradigm is forcing us to organize the data so that everything is accessible by <i>primary key</i>, speaking with relational DBs language.
<h2><a name="Following, followers and updates">Following, followers and updates</a></h2>
There is another central need in our system. Every user has followers users and following users. We have a perfect data structure for this work! That is... Sets. So let's add this two new fields to our schema:<br/><br/><pre class="codeblock python python python python python python python python python python python python python python" name="code">
uid:1000:followers =&gt; Set of uids of all the followers users
uid:1000:following =&gt; Set of uids of all the following users
</pre>Another important thing we need is a place were we can add the updates to display in the user home page. We'll need to access this data in chronological order later, from the most recent update to the older ones, so the perfect kind of Value for this work is a List. Basically every new update will be LPUSHed in the user updates key, and thanks to LRANGE we can implement pagination and so on. Note that we use the words <i>updates</i> and <i>posts</i> interchangeably, since updates are actually &quot;little posts&quot; in some way.<br/><br/><pre class="codeblock python python python python python python python python python python python python python python python" name="code">
uid:1000:posts =&gt; a List of post ids, every new post is LPUSHed here.
</pre>
<h2><a name="Authentication">Authentication</a></h2>
Ok we have more or less everything about the user, but authentication. We'll handle authentication in a simple but robust way: we don't want to use PHP sessions or other things like this, our system must be ready in order to be distributed among different servers, so we'll take the whole state in our Redis database. So all we need is a random string to set as the cookie of an authenticated user, and a key that will tell us what is the user ID of the client holding such a random string. We need two keys in order to make this thing working in a robust way:<br/><br/><pre class="codeblock python python python python python python python python python python python python python python python python" name="code">
SET uid:1000:auth fea5e81ac8ca77622bed1c2132a021f9
SET auth:fea5e81ac8ca77622bed1c2132a021f9 1000
</pre>In order to authenticate an user we'll do this simple work (login.php):
<ul><li> Get the username and password via the login form</li><li> Check if the username:<code name="code" class="python">&lt;username&gt;</code>:uid key actually exists</li><li> If it exists we have the user id, (i.e. 1000)</li><li> Check if uid:1000:password matches, if not, error message</li><li> Ok authenticated! Set &quot;fea5e81ac8ca77622bed1c2132a021f9&quot; (the value of uid:1000:auth) as &quot;auth&quot; cookie</li></ul>
This is the actual code:<br/><br/><pre class="codeblock python python python python python python python python python python python python python python python python python" name="code">
include(&quot;retwis.php&quot;);
# Form sanity checks
if (!gt(&quot;username&quot;) || !gt(&quot;password&quot;))
goback(&quot;You need to enter both username and password to login.&quot;);
# The form is ok, check if the username is available
$username = gt(&quot;username&quot;);
$password = gt(&quot;password&quot;);
$r = redisLink();
$userid = $r-&gt;get(&quot;username:$username:id&quot;);
if (!$userid)
goback(&quot;Wrong username or password&quot;);
$realpassword = $r-&gt;get(&quot;uid:$userid:password&quot;);
if ($realpassword != $password)
goback(&quot;Wrong useranme or password&quot;);
# Username / password OK, set the cookie and redirect to index.php
$authsecret = $r-&gt;get(&quot;uid:$userid:auth&quot;);
setcookie(&quot;auth&quot;,$authsecret,time()+3600*24*365);
header(&quot;Location: index.php&quot;);
</pre>This happens every time the users log in, but we also need a function isLoggedIn in order to check if a given user is already authenticated or not. These are the logical steps preformed by the <code name="code" class="python">isLoggedIn</code> function:
<ul><li> Get the &quot;auth&quot; cookie from the user. If there is no cookie, the user is not logged in, of course. Let's call the value of this cookie <code name="code" class="python">&lt;authcookie&gt;</code></li><li> Check if auth:<code name="code" class="python">&lt;authcookie&gt;</code> exists, and what the value (the user id) is (1000 in the exmple).</li><li> In order to be sure check that uid:1000:auth matches.</li><li> Ok the user is authenticated, and we loaded a bit of information in the $User global variable.</li></ul>
The code is simpler than the description, possibly:<br/><br/><pre class="codeblock python python python python python python python python python python python python python python python python python python" name="code">
function isLoggedIn() {
global $User, $_COOKIE;
if (isset($User)) return true;
if (isset($_COOKIE['auth'])) {
$r = redisLink();
$authcookie = $_COOKIE['auth'];
if ($userid = $r-&gt;get(&quot;auth:$authcookie&quot;)) {
if ($r-&gt;get(&quot;uid:$userid:auth&quot;) != $authcookie) return false;
loadUserInfo($userid);
return true;
}
}
return false;
}
function loadUserInfo($userid) {
global $User;
$r = redisLink();
$User['id'] = $userid;
$User['username'] = $r-&gt;get(&quot;uid:$userid:username&quot;);
return true;
}
</pre><code name="code" class="python">loadUserInfo</code> as separated function is an overkill for our application, but it's a good template for a complex application. The only thing it's missing from all the authentication is the logout. What we do on logout? That's simple, we'll just change the random string in uid:1000:auth, remove the old auth:<code name="code" class="python">&lt;oldauthstring&gt;</code> and add a new auth:<code name="code" class="python">&lt;newauthstring&gt;</code>.<br/><br/><b>Important:</b> the logout procedure explains why we don't just authenticate the user after the lookup of auth:<code name="code" class="python">&lt;randomstring&gt;</code>, but double check it against uid:1000:auth. The true authentication string is the latter, the auth:<code name="code" class="python">&lt;randomstring&gt;</code> is just an authentication key that may even be volatile, or if there are bugs in the program or a script gets interrupted we may even end with multiple auth:<code name="code" class="python">&lt;something&gt;</code> keys pointing to the same user id. The logout code is the following (logout.php):<br/><br/><pre class="codeblock python python python python python python python python python python python python python python python python python python python" name="code">
include(&quot;retwis.php&quot;);
if (!isLoggedIn()) {
header(&quot;Location: index.php&quot;);
exit;
}
$r = redisLink();
$newauthsecret = getrand();
$userid = $User['id'];
$oldauthsecret = $r-&gt;get(&quot;uid:$userid:auth&quot;);
$r-&gt;set(&quot;uid:$userid:auth&quot;,$newauthsecret);
$r-&gt;set(&quot;auth:$newauthsecret&quot;,$userid);
$r-&gt;delete(&quot;auth:$oldauthsecret&quot;);
header(&quot;Location: index.php&quot;);
</pre>That is just what we described and should be simple to undestand.
<h2><a name="Updates">Updates</a></h2>
Updates, also known as posts, are even simpler. In order to create a new post on the database we do something like this:<br/><br/><pre class="codeblock python python python python python python python python python python python python python python python python python python python python" name="code">
INCR global:nextPostId =&gt; 10343
SET post:10343 &quot;$owner_id|$time|I'm having fun with Retwis&quot;
</pre>As you can se the user id and time of the post are stored directly inside the string, we don't need to lookup by time or user id in the example application so it is better to compact everything inside the post string.<br/><br/>After we create a post we obtain the post id. We need to LPUSH this post id in every user that's following the author of the post, and of course in the list of posts of the author. This is the file update.php that shows how this is performed:<br/><br/><pre class="codeblock python python python python python python python python python python python python python python python python python python python python python" name="code">
include(&quot;retwis.php&quot;);
if (!isLoggedIn() || !gt(&quot;status&quot;)) {
header(&quot;Location:index.php&quot;);
exit;
}
$r = redisLink();
$postid = $r-&gt;incr(&quot;global:nextPostId&quot;);
$status = str_replace(&quot;\n&quot;,&quot; &quot;,gt(&quot;status&quot;));
$post = $User['id'].&quot;|&quot;.time().&quot;|&quot;.$status;
$r-&gt;set(&quot;post:$postid&quot;,$post);
$followers = $r-&gt;smembers(&quot;uid:&quot;.$User['id'].&quot;:followers&quot;);
if ($followers === false) $followers = Array();
$followers[] = $User['id']; /* Add the post to our own posts too */
foreach($followers as $fid) {
$r-&gt;push(&quot;uid:$fid:posts&quot;,$postid,false);
}
# Push the post on the timeline, and trim the timeline to the
# newest 1000 elements.
$r-&gt;push(&quot;global:timeline&quot;,$postid,false);
$r-&gt;ltrim(&quot;global:timeline&quot;,0,1000);
header(&quot;Location: index.php&quot;);
</pre>The core of the function is the <code name="code" class="python">foreach</code>. We get using SMEMBERS all the followers of the current user, then the loop will LPUSH the post against the uid:<code name="code" class="python">&lt;userid&gt;</code>:posts of every follower.<br/><br/>Note that we also maintain a timeline with all the posts. In order to do so what is needed is just to LPUSH the post against global:timeline. Let's face it, do you start thinking it was a bit strange to have to sort things added in chronological order using ORDER BY with SQL? I think so indeed.
<h2><a name="Paginating updates">Paginating updates</a></h2>
Now it should be pretty clear how we can user LRANGE in order to get ranges of posts, and render this posts on the screen. The code is simple:<br/><br/><pre class="codeblock python python python python python python python python python python python python python python python python python python python python python python" name="code">
function showPost($id) {
$r = redisLink();
$postdata = $r-&gt;get(&quot;post:$id&quot;);
if (!$postdata) return false;
$aux = explode(&quot;|&quot;,$postdata);
$id = $aux[0];
$time = $aux[1];
$username = $r-&gt;get(&quot;uid:$id:username&quot;);
$post = join(array_splice($aux,2,count($aux)-2),&quot;|&quot;);
$elapsed = strElapsed($time);
$userlink = &quot;&lt;a class=\&quot;username\&quot; href=\&quot;profile.php?u=&quot;.urlencode($username).&quot;\&quot;&gt;&quot;.utf8entities($username).&quot;&lt;/a&gt;&quot;;
echo('&lt;div class=&quot;post&quot;&gt;'.$userlink.' '.utf8entities($post).&quot;&lt;br&gt;&quot;);
echo('&lt;i&gt;posted '.$elapsed.' ago via web&lt;/i&gt;&lt;/div&gt;');
return true;
}
function showUserPosts($userid,$start,$count) {
$r = redisLink();
$key = ($userid == -1) ? &quot;global:timeline&quot; : &quot;uid:$userid:posts&quot;;
$posts = $r-&gt;lrange($key,$start,$start+$count);
$c = 0;
foreach($posts as $p) {
if (showPost($p)) $c++;
if ($c == $count) break;
}
return count($posts) == $count+1;
}
</pre><code name="code" class="python">showPost</code> will simply convert and print a Post in HTML while <code name="code" class="python">showUserPosts</code> get range of posts passing them to <code name="code" class="python">showPosts</code>.<h2><a name="Following users">Following users</a></h2>If user id 1000 (antirez) wants to follow user id 1001 (pippo), we can do this with just two SADD:<br/><br/><pre class="codeblock python python python python python python python python python python python python python python python python python python python python python python python" name="code">
SADD uid:1000:following 1001
SADD uid:1001:followers 1000
</pre>Note the same pattern again and again, in theory with a relational database the list of following and followers is a single table with fields like <code name="code" class="python">following_id</code> and <code name="code" class="python">follower_id</code>. With queries you can extract the followers or following of every user. With a key-value DB that's a bit different as we need to set both the <code name="code" class="python">1000 is following 1001</code> and <code name="code" class="python">1001 is followed by 1000</code> relations. This is the price to pay, but on the other side accessing the data is simpler and ultra-fast. And having this things as separated sets allows us to do interesting stuff, for example using SINTER we can have the intersection of 'following' of two different users, so we may add a feature to our Twitter clone so that it is able to say you at warp speed, when you visit somebody' else profile, &quot;you and foobar have 34 followers in common&quot; and things like that.<br/><br/>You can find the code that sets or removes a following/follower relation at follow.php. It is trivial as you can see.
<h1><a name="Making it horizontally scalable">Making it horizontally scalable</a></h1>
Gentle reader, if you reached this point you are already an hero, thank you. Before to talk about scaling horizontally it is worth to check the performances on a single server. Retwis is <b>amazingly fast</b>, without any kind of cache. On a very slow and loaded server, apache benchmark with 100 parallel clients issuing 100000 requests measured the average pageview to take 5 milliseconds. This means you can serve millions of users every day with just a single Linux box, and this one was monkey asses slow! Go figure with more recent hardware.<br/><br/>So, first of all, probably you will not need more than one server for a lot of applications, even when you have a lot of users. But let's assume we <b>are</b> Twitter and need to handle a huge amount of traffic. What to do?
<h3><a name="Hashing the key">Hashing the key</a></h3>
The first thing to do is to hash the key and issue the request on different servers based on the key hash. There are a lot of well known algorithms to do so, for example check the Redis Ruby library client that implements <i>consistent hashing</i>, but the general idea is that you can turn your key into a number, and than take the reminder of the division of this number by the number of servers you have:<br/><br/><pre class="codeblock python python python python python python python python python python python python python python python python python python python python python python python python" name="code">
server_id = crc32(key) % number_of_servers
</pre>This has a lot of problems since if you add one server you need to move too much keys and so on, but this is the general idea even if you use a better hashing scheme like consistent hashing.<br/><br/>Ok, are key accesses distributed among the key space? Well, all the user data will be partitioned among different servers. There are no inter-keys operations used (like SINTER, otherwise you need to care that things you want to intersect will end in the same server. <b>This is why Redis unlike memcached does not force a specific hashing scheme, it's application specific</b>). Btw there are keys that are accessed more frequently.<h3><a name="Special keys">Special keys</a></h3>For example every time we post a new message, we <b>need</b> to increment the <code name="code" class="python">global:nextPostId</code> key. How to fix this problem? A Single server will get a lot if increments. The simplest way to handle this is to have a dedicated server just for increments. This is probably an overkill btw unless you have really a lot of traffic. There is another trick. The ID does not really need to be an incremental number, but just <b>it needs to be unique</b>. So you can get a random string long enough to be unlikely (almost impossible, if it's md5-size) to collide, and you are done. We successfully eliminated our main problem to make it really horizontally scalable!<br/><br/>There is another one: global:timeline. There is no fix for this, if you need to take something in order you can split among different servers and <b>then merge</b> when you need to get the data back, or take it ordered and use a single key. Again if you really have so much posts per second, you can use a single server just for this. Remember that with commodity hardware Redis is able to handle 100000 writes for second, that's enough even for Twitter, I guess.<br/><br/>Please feel free to use the comments below for questions and feedbacks.
</div>
</div>
</div>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<link type="text/css" rel="stylesheet" href="style.css" />
</head>
<body>
<div id="page">
<div id='header'>
<a href="index.html">
<img style="border:none" alt="Redis Documentation" src="redis.png">
</a>
</div>
<div id="pagecontent">
<div class="index">
<!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
<b>TypeCommand: Contents</b><br>&nbsp;&nbsp;<a href="#TYPE _key_">TYPE _key_</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Return value">Return value</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#See also">See also</a>
</div>
<h1 class="wikiname">TypeCommand</h1>
<div class="summary">
</div>
<div class="narrow">
&iuml;&raquo;&iquest;#sidebar <a href="GenericCommandsSidebar.html">GenericCommandsSidebar</a><h1><a name="TYPE _key_">TYPE _key_</a></h1>
<i>Time complexity: O(1)</i><blockquote>Return the type of the value stored at <i>key</i> in form of astring. The type can be one of &quot;none&quot;, &quot;string&quot;, &quot;list&quot;, &quot;set&quot;.&quot;none&quot; is returned if the key does not exist.</blockquote>
<h2><a name="Return value">Return value</a></h2><a href="ReplyTypes.html">Status code reply</a>, specifically:<br/><br/><pre class="codeblock python" name="code">
&quot;none&quot; if the key does not exist
&quot;string&quot; if the key contains a String value
&quot;list&quot; if the key contains a List value
&quot;set&quot; if the key contains a Set value
&quot;zset&quot; if the key contains a Sorted Set value
&quot;hash&quot; if the key contains a Hash value
</pre><h2><a name="See also">See also</a></h2>
<ul><li> <a href="DataTypes.html">Redis Data Types</a></li></ul>
</div>
</div>
</div>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<link type="text/css" rel="stylesheet" href="style.css" />
</head>
<body>
<div id="page">
<div id='header'>
<a href="index.html">
<img style="border:none" alt="Redis Documentation" src="redis.png">
</a>
</div>
<div id="pagecontent">
<div class="index">
<!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
<b>UnstableSource: Contents</b><br>&nbsp;&nbsp;<a href="#Get the latest Redis source code">Get the latest Redis source code</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Unstable code">Unstable code</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Stable code">Stable code</a>
</div>
<h1 class="wikiname">UnstableSource</h1>
<div class="summary">
</div>
<div class="narrow">
<h1><a name="Get the latest Redis source code">Get the latest Redis source code</a></h1><h2><a name="Unstable code">Unstable code</a></h2>
The development version of Redis is <a href="http://github.com/antirez/redis/tree/master" target="_blank">hosted here at Github</a>, have fun cloning the source code with Git. If you are not familar with Git just use the <b>download</b> button to get a tarball.<h2><a name="Stable code">Stable code</a></h2>
<b>Warning:</b> the development source code is only intended for people that want to develop Redis or absolutely need the latest features still not available on the stable releases. You may have a better experience with the <a href="http://code.google.com/p/redis/downloads/list" target="_blank">latest stable tarball</a>.
</div>
</div>
</div>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<link type="text/css" rel="stylesheet" href="style.css" />
</head>
<body>
<div id="page">
<div id='header'>
<a href="index.html">
<img style="border:none" alt="Redis Documentation" src="redis.png">
</a>
</div>
<div id="pagecontent">
<div class="index">
<!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
<b>VirtualMemorySpecification: Contents</b><br>&nbsp;&nbsp;<a href="#Virtual Memory technical specification">Virtual Memory technical specification</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Keys vs Values: what is swapped out?">Keys vs Values: what is swapped out?</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#How does a swapped value looks like internally">How does a swapped value looks like internally</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#The Swap File">The Swap File</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Transfering objects from memory to swap">Transfering objects from memory to swap</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Loading objects back in memory">Loading objects back in memory</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#How blocking VM works">How blocking VM works</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Blocking VM swapping">Blocking VM swapping</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#What values to swap when we are out of memory?">What values to swap when we are out of memory?</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Blocking VM loading">Blocking VM loading</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Background saving when VM is active">Background saving when VM is active</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#The problem with the blocking VM">The problem with the blocking VM</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Threaded VM">Threaded VM</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#I/O Threads">I/O Threads</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Non blocking VM as probabilistic enhancement of blocking VM">Non blocking VM as probabilistic enhancement of blocking VM</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Blocking clients on swapped keys">Blocking clients on swapped keys</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Aborting I/O jobs">Aborting I/O jobs</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Questions?">Questions?</a>
</div>
<h1 class="wikiname">VirtualMemorySpecification</h1>
<div class="summary">
</div>
<div class="narrow">
&iuml;&raquo;&iquest;#sidebar <a href="RedisInternals.html">RedisInternals</a><h1><a name="Virtual Memory technical specification">Virtual Memory technical specification</a></h1>This document details the internals of the Redis Virtual Memory subsystem. The intended audience is not the final user but programmers willing to understand or modify the Virtual Memory implementation.<h2><a name="Keys vs Values: what is swapped out?">Keys vs Values: what is swapped out?</a></h2>
The goal of the VM subsystem is to free memory transferring Redis Objects from memory to disk. This is a very generic command, but specifically, Redis transfers only objects associated with <i>values</i>. In order to understand better this concept we'll show, using the DEBUG command, how a key holding a value looks from the point of view of the Redis internals:
<pre class="codeblock python" name="code">
redis&gt; set foo bar
OK
redis&gt; debug object foo
Key at:0x100101d00 refcount:1, value at:0x100101ce0 refcount:1 encoding:raw serializedlength:4
</pre>
As you can see from the above output, the Redis top level hash table maps Redis Objects (keys) to other Redis Objects (values). The Virtual Memory is only able to swap <i>values</i> on disk, the objects associated to <i>keys</i> are always taken in memory: this trade off guarantees very good lookup performances, as one of the main design goals of the Redis VM is to have performances similar to Redis with VM disabled when the part of the dataset frequently used fits in RAM.<h2><a name="How does a swapped value looks like internally">How does a swapped value looks like internally</a></h2>
When an object is swapped out, this is what happens in the hash table entry:
<ul><li> The key continues to hold a Redis Object representing the key.</li><li> The value is set to NULL</li></ul>So you may wonder where we store the information that a given value (associated to a given key) was swapped out. Just in the key object!<br/><br/>This is how the Redis Object structure <i>robj</i> looks like:
<pre class="codeblock python python" name="code">
/* The actual Redis Object */
typedef struct redisObject {
void *ptr;
unsigned char type;
unsigned char encoding;
unsigned char storage; /* If this object is a key, where is the value?
* REDIS_VM_MEMORY, REDIS_VM_SWAPPED, ... */
unsigned char vtype; /* If this object is a key, and value is swapped out,
* this is the type of the swapped out object. */
int refcount;
/* VM fields, this are only allocated if VM is active, otherwise the
* object allocation function will just allocate
* sizeof(redisObjct) minus sizeof(redisObjectVM), so using
* Redis without VM active will not have any overhead. */
struct redisObjectVM vm;
} robj;
</pre>
As you can see there are a few fields about VM. The most important one is <i>storage</i>, that can be one of this values:
<ul><li> REDIS_VM_MEMORY: the associated value is in memory.</li><li> REDIS_VM_SWAPPED: the associated values is swapped, and the value entry of the hash table is just set to NULL.</li><li> REDIS_VM_LOADING: the value is swapped on disk, the entry is NULL, but there is a job to load the object from the swap to the memory (this field is only used when threaded VM is active).</li><li> REDIS_VM_SWAPPING: the value is in memory, the entry is a pointer to the actual Redis Object, but there is an I/O job in order to transfer this value to the swap file.</li></ul>If an object is swapped on disk (REDIS_VM_SWAPPED or REDIS_VM_LOADING), how do we know where it is stored, what type it is, and so forth? That's simple: the <i>vtype</i> field is set to the original type of the Redis object swapped, while the <i>vm</i> field (that is a <i>redisObjectVM</i> structure) holds information about the location of the object. This is the definition of this additional structure:
<pre class="codeblock python python python" name="code">
/* The VM object structure */
struct redisObjectVM {
off_t page; /* the page at which the object is stored on disk */
off_t usedpages; /* number of pages used on disk */
time_t atime; /* Last access time */
} vm;
</pre>
As you can see the structure contains the page at which the object is located in the swap file, the number of pages used, and the last access time of the object (this is very useful for the algorithm that select what object is a good candidate for swapping, as we want to transfer on disk objects that are rarely accessed).<br/><br/>As you can see, while all the other fields are using unused bytes in the old Redis Object structure (we had some free bit due to natural memory alignment concerns), the <i>vm</i> field is new, and indeed uses additional memory. Should we pay such a memory cost even when VM is disabled? No! This is the code to create a new Redis Object:
<pre class="codeblock python python python python" name="code">
... some code ...
if (server.vm_enabled) {
pthread_mutex_unlock(&amp;server.obj_freelist_mutex);
o = zmalloc(sizeof(*o));
} else {
o = zmalloc(sizeof(*o)-sizeof(struct redisObjectVM));
}
... some code ...
</pre>
As you can see if the VM system is not enabled we allocate just <code name="code" class="python">sizeof(*o)-sizeof(struct redisObjectVM)</code> of memory. Given that the <i>vm</i> field is the last in the object structure, and that this fields are never accessed if VM is disabled, we are safe and Redis without VM does not pay the memory overhead.<h2><a name="The Swap File">The Swap File</a></h2>
The next step in order to understand how the VM subsystem works is understanding how objects are stored inside the swap file. The good news is that's not some kind of special format, we just use the same format used to store the objects in .rdb files, that are the usual dump files produced by Redis using the SAVE command.<br/><br/>The swap file is composed of a given number of pages, where every page size is a given number of bytes. This parameters can be changed in redis.conf, since different Redis instances may work better with different values: it depends on the actual data you store inside it. The following are the default values:
<pre class="codeblock python python python python python" name="code">
vm-page-size 32
vm-pages 134217728
</pre>
Redis takes a &quot;bitmap&quot; (an contiguous array of bits set to zero or one) in memory, every bit represent a page of the swap file on disk: if a given bit is set to 1, it represents a page that is already used (there is some Redis Object stored there), while if the corresponding bit is zero, the page is free.<br/><br/>Taking this bitmap (that will call the page table) in memory is a huge win in terms of performances, and the memory used is small: we just need 1 bit for every page on disk. For instance in the example below 134217728 pages of 32 bytes each (4GB swap file) is using just 16 MB of RAM for the page table.<h2><a name="Transfering objects from memory to swap">Transfering objects from memory to swap</a></h2>
In order to transfer an object from memory to disk we need to perform the following steps (assuming non threaded VM, just a simple blocking approach):<br/><br/><ul><li> Find how many pages are needed in order to store this object on the swap file. This is trivially accomplished just calling the function <code name="code" class="python">rdbSavedObjectPages</code> that returns the number of pages used by an object on disk. Note that this function does not duplicate the .rdb saving code just to understand what will be the length <b>after</b> an object will be saved on disk, we use the trick of opening /dev/null and writing the object there, finally calling <code name="code" class="python">ftello</code> in order check the amount of bytes required. What we do basically is to save the object on a virtual very fast file, that is, /dev/null.</li><li> Now that we know how many pages are required in the swap file, we need to find this number of contiguous free pages inside the swap file. This task is accomplished by the <code name="code" class="python">vmFindContiguousPages</code> function. As you can guess this function may fail if the swap is full, or so fragmented that we can't easily find the required number of contiguous free pages. When this happens we just abort the swapping of the object, that will continue to live in memory.</li><li> Finally we can write the object on disk, at the specified position, just calling the function <code name="code" class="python">vmWriteObjectOnSwap</code>.</li></ul>As you can guess once the object was correctly written in the swap file, it is freed from memory, the storage field in the associated key is set to REDIS_VM_SWAPPED, and the used pages are marked as used in the page table.
<h2><a name="Loading objects back in memory">Loading objects back in memory</a></h2>
Loading an object from swap to memory is simpler, as we already know where the object is located and how many pages it is using. We also know the type of the object (the loading functions are required to know this information, as there is no header or any other information about the object type on disk), but this is stored in the <i>vtype</i> field of the associated key as already seen above.<br/><br/>Calling the function <code name="code" class="python">vmLoadObject</code> passing the key object associated to the value object we want to load back is enough. The function will also take care of fixing the storage type of the key (that will be REDIS_VM_MEMORY), marking the pages as freed in the page table, and so forth.<br/><br/>The return value of the function is the loaded Redis Object itself, that we'll have to set again as value in the main hash table (instead of the NULL value we put in place of the object pointer when the value was originally swapped out).
<h2><a name="How blocking VM works">How blocking VM works</a></h2>
Now we have all the building blocks in order to describe how the blocking VM works. First of all, an important detail about configuration. In order to enable blocking VM in Redis <code name="code" class="python">server.vm_max_threads</code> must be set to zero.
We'll see later how this max number of threads info is used in the threaded VM, for now all it's needed to now is that Redis reverts to fully blocking VM when this is set to zero.<br/><br/>We also need to introduce another important VM parameter, that is, <code name="code" class="python">server.vm_max_memory</code>. This parameter is very important as it is used in order to trigger swapping: Redis will try to swap objects only if it is using more memory than the max memory setting, otherwise there is no need to swap as we are matching the user requested memory usage.
<h2><a name="Blocking VM swapping">Blocking VM swapping</a></h2>
Swapping of object from memory to disk happens in the cron function. This function used to be called every second, while in the recent Redis versions on git it is called every 100 milliseconds (that is, 10 times per second).
If this function detects we are out of memory, that is, the memory used is greater than the vm-max-memory setting, it starts transferring objects from memory to disk in a loop calling the function <code name="code" class="python">vmSwapOneObect</code>. This function takes just one argument, if 0 it will swap objects in a blocking way, otherwise if it is 1, I/O threads are used. In the blocking scenario we just call it with zero as argument.<br/><br/>vmSwapOneObject acts performing the following steps:
<ul><li> The key space in inspected in order to find a good candidate for swapping (we'll see later what a good candidate for swapping is).</li><li> The associated value is transfered to disk, in a blocking way.</li><li> The key storage field is set to REDIS_VM_SWAPPED, while the <i>vm</i> fields of the object are set to the right values (the page index where the object was swapped, and the number of pages used to swap it).</li><li> Finally the value object is freed and the value entry of the hash table is set to NULL.</li></ul>The function is called again and again until one of the following happens: there is no way to swap more objects because either the swap file is full or nearly all the objects are already transfered on disk, or simply the memory usage is already under the vm-max-memory parameter.
<h2><a name="What values to swap when we are out of memory?">What values to swap when we are out of memory?</a></h2>
Understanding what's a good candidate for swapping is not too hard. A few objects at random are sampled, and for each their <i>swappability</i> is commuted as:
<pre class="codeblock python python python python python python" name="code">
swappability = age*log(size_in_memory)
</pre>
The age is the number of seconds the key was not requested, while size_in_memory is a fast estimation of the amount of memory (in bytes) used by the object in memory. So we try to swap out objects that are rarely accessed, and we try to swap bigger objects over smaller one, but the latter is a less important factor (because of the logarithmic function used). This is because we don't want bigger objects to be swapped out and in too often as the bigger the object the more I/O and CPU is required in order to transfer it.
<h2><a name="Blocking VM loading">Blocking VM loading</a></h2>
What happens if an operation against a key associated with a swapped out object is requested? For instance Redis may just happen to process the following command:
<pre class="codeblock python python python python python python python" name="code">
GET foo
</pre>
If the value object of the <code name="code" class="python">foo</code> key is swapped we need to load it back in memory before processing the operation. In Redis the key lookup process is centralized in the <code name="code" class="python">lookupKeyRead</code> and <code name="code" class="python">lookupKeyWrite</code> functions, this two functions are used in the implementation of all the Redis commands accessing the keyspace, so we have a single point in the code where to handle the loading of the key from the swap file to memory.<br/><br/>So this is what happens:
<ul><li> The user calls some command having as argumenet a swapped key</li><li> The command implementation calls the lookup function</li><li> The lookup function search for the key in the top level hash table. If the value associated with the requested key is swapped (we can see that checking the <i>storage</i> field of the key object), we load it back in memory in a blocking way before to return to the user.</li></ul>
This is pretty straightforward, but things will get more <i>interesting</i> with the threads. From the point of view of the blocking VM the only real problem is the saving of the dataset using another process, that is, handling BGSAVE and BGREWRITEAOF commands.
<h2><a name="Background saving when VM is active">Background saving when VM is active</a></h2>
The default Redis way to persist on disk is to create .rdb files using a child process. Redis calls the fork() system call in order to create a child, that has the exact copy of the in memory dataset, since fork duplicates the whole program memory space (actually thanks to a technique called Copy on Write memory pages are shared between the parent and child process, so the fork() call will not require too much memory).<br/><br/>In the child process we have a copy of the dataset in a given point in the time. Other commands issued by clients will just be served by the parent process and will not modify the child data.<br/><br/>The child process will just store the whole dataset into the dump.rdb file and finally will exit. But what happens when the VM is active? Values can be swapped out so we don't have all the data in memory, and we need to access the swap file in order to retrieve the swapped values. While child process is saving the swap file is shared between the parent and child process, since:
<ul><li> The parent process needs to access the swap file in order to load values back into memory if an operation against swapped out values are performed.</li><li> The child process needs to access the swap file in order to retrieve the full dataset while saving the data set on disk.</li></ul>In order to avoid problems while both the processes are accessing the same swap file we do a simple thing, that is, not allowing values to be swapped out in the parent process while a background saving is in progress. This way both the processes will access the swap file in read only. This approach has the problem that while the child process is saving no new values can be transfered on the swap file even if Redis is using more memory than the max memory parameters dictates. This is usually not a problem as the background saving will terminate in a short amount of time and if still needed a percentage of values will be swapped on disk ASAP.<br/><br/>An alternative to this scenario is to enable the Append Only File that will have this problem only when a log rewrite is performed using the BGREWRITEAOF command.
<h2><a name="The problem with the blocking VM">The problem with the blocking VM</a></h2>
The problem of blocking VM is that... it's blocking :)
This is not a problem when Redis is used in batch processing activities, but for real-time usage one of the good points of Redis is the low latency. The blocking VM will have bad latency behaviors as when a client is accessing a swapped out value, or when Redis needs to swap out values, no other clients will be served in the meantime.<br/><br/>Swapping out keys should happen in background. Similarly when a client is accessing a swapped out value other clients accessing in memory values should be served mostly as fast as when VM is disabled. Only the clients dealing with swapped out keys should be delayed.<br/><br/>All this limitations called for a non-blocking VM implementation.
<h2><a name="Threaded VM">Threaded VM</a></h2>
There are basically three main ways to turn the blocking VM into a non blocking one.
<ul><li> 1: One way is obvious, and in my opionion, not a good idea at all, that is, turning Redis itself into a theaded server: if every request is served by a different thread automatically other clients don't need to wait for blocked ones. Redis is fast, exports atomic operations, has no locks, and is just 10k lines of code, <b>because</b> it is single threaded, so this was not an option for me.</li><li> 2: Using non-blocking I/O against the swap file. After all you can think Redis already event-loop based, why don't just handle disk I/O in a non-blocking fashion? I also discarded this possiblity because of two main reasons. One is that non blocking file operations, unlike sockets, are an incompatibility nightmare. It's not just like calling select, you need to use OS-specific things. The other problem is that the I/O is just one part of the time consumed to handle VM, another big part is the CPU used in order to encode/decode data to/from the swap file. This is I picked option three, that is...</li><li> 3: Using I/O threads, that is, a pool of threads handling the swap I/O operations. This is what the Redis VM is using, so let's detail how this works.</li></ul><h2><a name="I/O Threads">I/O Threads</a></h2>
The threaded VM design goals where the following, in order of importance:
<ul><li> Simple implementation, little room for race condtions, simple locking, VM system more or less completeley decoupled from the rest of Redis code.</li><li> Good performances, no locks for clients accessing values in memory.</li><li> Ability to decode/encode objects in the I/O threads.</li></ul>The above goals resulted in an implementation where the Redis main thread (the one serving actual clients) and the I/O threads communicate using a queue of jobs, with a single mutex.
Basically when main thread requires some work done in the background by some I/O thread, it pushes an I/O job structure in the <code name="code" class="python">server.io_newjobs</code> queue (that is, just a linked list). If there are no active I/O threads, one is started. At this point some I/O thread will process the I/O job, and the result of the processing is pushed in the <code name="code" class="python">server.io_processed</code> queue. The I/O thread will send a byte using an UNIX pipe to the main thread in order to signal that a new job was processed and the result is ready to be processed.<br/><br/>This is how the <code name="code" class="python">iojob</code> structure looks like:
<pre class="codeblock python python python python python python python python" name="code">
typedef struct iojob {
int type; /* Request type, REDIS_IOJOB_* */
redisDb *db;/* Redis database */
robj *key; /* This I/O request is about swapping this key */
robj *val; /* the value to swap for REDIS_IOREQ_*_SWAP, otherwise this
* field is populated by the I/O thread for REDIS_IOREQ_LOAD. */
off_t page; /* Swap page where to read/write the object */
off_t pages; /* Swap pages needed to save object. PREPARE_SWAP return val */
int canceled; /* True if this command was canceled by blocking side of VM */
pthread_t thread; /* ID of the thread processing this entry */
} iojob;
</pre>
There are just three type of jobs that an I/O thread can perform (the type is specified by the <code name="code" class="python">type</code> field of the structure):
<ul><li> REDIS_IOJOB_LOAD: load the value associated to a given key from swap to memory. The object offset inside the swap file is <code name="code" class="python">page</code>, the object type is <code name="code" class="python">key-&gt;vtype</code>. The result of this operation will populate the <code name="code" class="python">val</code> field of the structure.</li><li> REDIS_IOJOB_PREPARE_SWAP: compute the number of pages needed in order to save the object pointed by <code name="code" class="python">val</code> into the swap. The result of this operation will populate the <code name="code" class="python">pages</code> field.</li><li> REDIS_IOJOB_DO_SWAP: Transfer the object pointed by <code name="code" class="python">val</code> to the swap file, at page offset <code name="code" class="python">page</code>.</li></ul>The main thread delegates just the above three tasks. All the rest is handled by the main thread itself, for instance finding a suitable range of free pages in the swap file page table (that is a fast operation), deciding what object to swap, altering the storage field of a Redis object to reflect the current state of a value.
<h2><a name="Non blocking VM as probabilistic enhancement of blocking VM">Non blocking VM as probabilistic enhancement of blocking VM</a></h2>
So now we have a way to request background jobs dealing with slow VM operations. How to add this to the mix of the rest of the work done by the main thread? While blocking VM was aware that an object was swapped out just when the object was looked up, this is too late for us: in C it is not trivial to start a background job in the middle of the command, leave the function, and re-enter in the same point the computation when the I/O thread finished what we requested (that is, no co-routines or continuations or alike).<br/><br/>Fortunately there was a much, much simpler way to do this. And we love simple things: basically consider the VM implementation a blocking one, but add an optimization (using non the no blocking VM operations we are able to perform) to make the blocking <b>very</b> unlikely.<br/><br/>This is what we do:
<ul><li> Every time a client sends us a command, <b>before</b> the command is executed, we examine the argument vector of the command in search for swapped keys. After all we know for every command what arguments are keys, as the Redis command format is pretty simple.</li><li> If we detect that at least a key in the requested command is swapped on disk, we block the client instead of really issuing the command. For every swapped value associated to a requested key, an I/O job is created, in order to bring the values back in memory. The main thread continues the execution of the event loop, without caring about the blocked client.</li><li> In the meanwhile, I/O threads are loading values in memory. Every time an I/O thread finished loading a value, it sends a byte to the main thread using an UNIX pipe. The pipe file descriptor has a readable event associated in the main thread event loop, that is the function <code name="code" class="python">vmThreadedIOCompletedJob</code>. If this function detects that all the values needed for a blocked client were loaded, the client is restarted and the original command called.</li></ul>
So you can think at this as a blocked VM that almost always happen to have the right keys in memory, since we pause clients that are going to issue commands about swapped out values until this values are loaded.<br/><br/>If the function checking what argument is a key fails in some way, there is no problem: the lookup function will see that a given key is associated to a swapped out value and will block loading it. So our non blocking VM reverts to a blocking one when it is not possible to anticipate what keys are touched.<br/><br/>For instance in the case of the SORT command used together with the GET or BY options, it is not trivial to know beforehand what keys will be requested, so at least in the first implementation, SORT BY/GET resorts to the blocking VM implementation.
<h2><a name="Blocking clients on swapped keys">Blocking clients on swapped keys</a></h2>
How to block clients? To suspend a client in an event-loop based server is pretty trivial. All we do is cancelling its read handler. Sometimes we do something different (for instance for BLPOP) that is just marking the client as blocked, but not processing new data (just accumulating the new data into input buffers).
<h2><a name="Aborting I/O jobs">Aborting I/O jobs</a></h2>
There is something hard to solve about the interactions between our blocking and non blocking VM, that is, what happens if a blocking operation starts about a key that is also &quot;interested&quot; by a non blocking operation at the same time?<br/><br/>For instance while SORT BY is executed, a few keys are being loaded in a blocking manner by the sort command. At the same time, another client may request the same keys with a simple <i>GET key</i> command, that will trigger the creation of an I/O job to load the key in background.<br/><br/>The only simple way to deal with this problem is to be able to kill I/O jobs in the main thread, so that if a key that we want to load or swap in a blocking way is in the REDIS_VM_LOADING or REDIS_VM_SWAPPING state (that is, there is an I/O job about this key), we can just kill the I/O job about this key, and go ahead with the blocking operation we want to perform.<br/><br/>This is not as trivial as it is. In a given moment an I/O job can be in one of the following three queues:
<ul><li> server.io_newjobs: the job was already queued but no thread is handling it.</li><li> server.io_processing: the job is being processed by an I/O thread.</li><li> server.io_processed: the job was already processed.</li></ul>The function able to kill an I/O job is <code name="code" class="python">vmCancelThreadedIOJob</code>, and this is what it does:
<ul><li> If the job is in the newjobs queue, that's simple, removing the iojob structure from the queue is enough as no thread is still executing any operation.</li><li> If the job is in the processing queue, a thread is messing with our job (and possibly with the associated object!). The only thing we can do is waiting for the item to move to the next queue in a <b>blocking way</b>. Fortunately this condition happens very rarely so it's not a performance problem.</li><li> If the job is in the processed queue, we just mark it as <i>canceled</i> marking setting the <code name="code" class="python">canceled</code> field to 1 in the iojob structure. The function processing completed jobs will just ignored and free the job instead of really processing it.</li></ul>
<h2><a name="Questions?">Questions?</a></h2>
This document is in no way complete, the only way to get the whole picture is reading the source code, but it should be a good introduction in order to make the code review / understanding a lot simpler.<br/><br/>Something is not clear about this page? Please leave a comment and I'll try to address the issue possibly integrating the answer in this document.
</div>
</div>
</div>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<link type="text/css" rel="stylesheet" href="style.css" />
</head>
<body>
<div id="page">
<div id='header'>
<a href="index.html">
<img style="border:none" alt="Redis Documentation" src="redis.png">
</a>
</div>
<div id="pagecontent">
<div class="index">
<!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
<b>VirtualMemoryUserGuide: Contents</b><br>&nbsp;&nbsp;<a href="#Virtual Memory User Guide">Virtual Memory User Guide</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Virtual Memory explained in simple words">Virtual Memory explained in simple words</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#When using Virtual Memory is a good idea">When using Virtual Memory is a good idea</a><br>&nbsp;&nbsp;<a href="#VM Configuration">VM Configuration</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#The vm-max-memory setting">The vm-max-memory setting</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Configuring the swap file">Configuring the swap file</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Threaded VM vs Blocking VM">Threaded VM vs Blocking VM</a><br>&nbsp;&nbsp;<a href="#Random things to know">Random things to know</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#A good place for the swap file">A good place for the swap file</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Monitoring the VM">Monitoring the VM</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Redis with VM enabled: better .rdb files or Append Only File?">Redis with VM enabled: better .rdb files or Append Only File?</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Using as little memory as possible">Using as little memory as possible</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#VM Stability">VM Stability</a>
</div>
<h1 class="wikiname">VirtualMemoryUserGuide</h1>
<div class="summary">
</div>
<div class="narrow">
&iuml;&raquo;&iquest;#sidebar <a href="RedisGuides.html">RedisGuides</a><h1><a name="Virtual Memory User Guide">Virtual Memory User Guide</a></h1>Redis Virtual Memory is a feature that will appear for the first time in a stable Redis distribution in Redis 2.0. However Virtual Memory (called VM starting from now) is already available and stable enough to be tests in the unstable branch of Redis available <a href="http://github.com/antirez/redis" target="_blank">on Git</a>.<h2><a name="Virtual Memory explained in simple words">Virtual Memory explained in simple words</a></h2>Redis follows a Key-Value model. You have keys associated with some values.
Usually Redis takes both Keys and associated Values in memory. Sometimes this is not the best option, and while Keys <b>must</b> be taken in memory for the way Redis is designed (and in order to ensure fast lookups), Values can be swapped out to disk when they are rarely used.<br/><br/>In practical terms this means that if you have a dataset of 100,000 keys in memory, but only 10% of this keys are often used, Redis with Virtual Memory enabled will try to transfer the values associated to the rarely used keys on disk.<br/><br/>When this values are requested, as a result of a command issued by a client, the values are loaded back from the swap file to the main memory.<h2><a name="When using Virtual Memory is a good idea">When using Virtual Memory is a good idea</a></h2>Before using VM you should ask yourself if you really need it. Redis is a disk backed, in memory database. The right way to use Redis is almost always to have enough RAM to fit all the data in memory. Still there are a scenarios where to hold all the data in memory is not possible:
<ul><li> Data access is very biased. Only a small percentage of keys (for instance related to active users in your web site) gets the vast majority of accesses. At the same time there is too much data per key to take everything in memory.</li><li> There is simply not enough memory available to hold all the data in memory, regardless of the data access pattern, and values are large. In this configuration Redis can be used as an on-disk DB where keys are in memory, so the key lookup is fast, but the access to the actual values require accessing the (slower) disk.</li></ul>
An important concept to take in mind is that Redis <b>is not able to swap the keys</b>, so if your memory problems are related to the fact you have too much keys with very small values, VM is not the solution.<br/><br/>Instead if a good amount of memory is used because values are pretty large (for example large strings, lists, sets or hashes with many elements), then VM can be a good idea.<br/><br/>Sometimes you can turn your &quot;many keys with small values&quot; problem into a &quot;less keys but with very large values&quot; one just using Hashes in order to group related data into fields of a single key. For instance instead of having a key for every attribute of your object you have a single key per object where Hash fields represent the different attributes.<h1><a name="VM Configuration">VM Configuration</a></h1>Configuring the VM is not hard but requires some care to set the best parameters accordingly to the requirements.<br/><br/>The VM is enabled and configured editing redis.conf, the first step is switching it on with:<br/><br/><pre class="codeblock python" name="code">
vm-enabled yes
</pre>Many other configuration options are able to change the behavior of VM. The rule is that you don't want to run with the default configuration, as every problem and dataset requires some tuning in order to get the maximum advantages.<h2><a name="The vm-max-memory setting">The vm-max-memory setting</a></h2>The <b>vm-max-memory</b> setting specifies how much memory Redis is free to use before starting swapping values on disk.<br/><br/>Basically if this memory limit is still not reached, no object will be swapped, Redis will work all in memory as usually. Once this limit is hit, enough objects are swapped out in order to return just under the limit.<br/><br/>The swapped objects are the one with the highest &quot;age&quot; (that is, the number of seconds since they are not used in any way) mainly, but the &quot;swappability&quot; of an object is also proportional to the logarithm of it's size in memory. So basically older objects are preferred, but when they are about the same size, bigger objects are preferred.<br/><br/><b>WARNING:</b> Because keys can't be swapped out, Redis will not be able to honour the <b>vm-max-memory</b> setting if the keys alone are using more space than the limit.<br/><br/>The best value for this setting is enough RAM in order to hold the &quot;working set&quot; of data. In practical terms, just give Redis as much memory as you can, and swapping will work better.<h2><a name="Configuring the swap file">Configuring the swap file</a></h2>In order to transfer data from memory to disk, Redis uses a swap file. The swap file has nothing to do with durability of data, and can be removed when a Redis instance is terminated. Still the swap file should not be moved, deleted, or altered in any other way while Redis is running.<br/><br/>Because the Redis swap file is used mostly in a random access fashion, to put the swap file into a Solid State Disk will lead to better performances.<br/><br/>The swap file is divided into &quot;pages&quot;. A value can be swapped into one or multiple pages, but a single page can't hold more than a value.<br/><br/>There is no direct way to tell Redis how much bytes of swap file it should be using. Instead two different values are configured, that multiplied together will produce the total number of bytes used. This two values are the number of pages inside the swap file, and the page size. It is possible to configure this two parameters in redis.conf.<br/><br/><ul><li> The <b>vm-pages</b> configuration directive is used to set the total number of pages in the swap file.</li><li> the <b>vm-page-size</b> configuration directive is used in order to set the page size in bytes.</li></ul>
So for instance if the page size is set to the value of 32 bytes, and the total number of pages is set to 10000000 (10 millions), the swap file can hold a total of 320 MB of data.<br/><br/>Because a single page can't be used to hold more than a value (but a value can be stored into multiple pages), care must be taken in setting this parameters.
Usually the best idea is setting the page size so that the majority of the values can be swapped using a few pages.<h2><a name="Threaded VM vs Blocking VM">Threaded VM vs Blocking VM</a></h2>Another very important configuration parameter is <b>vm-max-threads</b>:<br/><br/><pre class="codeblock python python" name="code">
# The default vm-max-threads configuration
vm-max-threads 4
</pre>This is the maximum number of threads used in order to perform I/O from/to the swap file. A good value is just to match the number of cores in your system.<br/><br/>However the special value of &quot;0&quot; will enable blocking VM. When VM is configured to be blocking it performs the I/O in a synchronous blocking way. This is what you can expect from blocking VM:
<ul><li> Clients accessing swapped out keys will block other clients while reading from disk, so the latency experimented by clients can be larger, especially if the disk is slow or busy and/or if there are big values swapped on disk.</li><li> The blocking VM performances are <b>overall</b> better, as there is no time lost in synchronization, spawning of threads, resuming blocked clients waiting for values.</li></ul>So if you are willing to accept an higher latency from time to time, blocking VM can be a good pick, especially if swapping happens rarely as most of your often accessed data happens to fit in your memory.<br/><br/>If instead you have a lot of swap in and swap out operations and you have many cores that you want to exploit, and in general when you don't want that clients dealing with swapped values will block other clients for a few milliseconds (or more if the swapped value is very big), then it's better to use threaded VM.<br/><br/>To experiment with your dataset and different configurations is warmly encouraged...<h1><a name="Random things to know">Random things to know</a></h1>
<h2><a name="A good place for the swap file">A good place for the swap file</a></h2>In many configurations the swap file can be fairly large, even 40GB or more.
Not all the kind of file systems are able to deal with large files in a good way, especially Mac OS X file system tends to be really lame about it.<br/><br/>The suggestion is to use Linux ext3 file system, or any other file system with good support for <b>sparse files</b>. What are sparse files?<br/><br/>Sparse files are files where a lot of the content happen to be empty. Advanced file systems like ext2, ext3, ext4, RaiserFS, Raiser4, and many others, are able to encode this files in a more efficient way and will allocate more space for the file when needed, that is, when more actual blocks of the file will be used.<br/><br/>The swap file is obviously pretty sparse, especially if the server is running since little time or it is much bigger compared to the amount of data swapped out. A file system not supporting sparse files can at some point block the Redis process while creating a very big file at once.<br/><br/>For a list of file systems supporting spare files <a href="http://en.wikipedia.org/wiki/Comparison_of_file_systems" target="_blank">check this Wikipedia page comparing different files systems</a>.<h2><a name="Monitoring the VM">Monitoring the VM</a></h2>Once you have a Redis system with VM enabled up and running, you may be very interested in knowing how it's working: how many objects are swapped in total, the number of objects swapped and loaded every second, and so forth.<br/><br/>There is an utility that is very handy in checking how the VM is working, that is part of <a href="http://github.com/antirez/redis-tools" target="_blank">Redis Tools</a>. This tool is called redis-stat, and using it is pretty straightforward:<br/><br/><pre class="codeblock python python python" name="code">
$ ./redis-stat vmstat
--------------- objects --------------- ------ pages ------ ----- memory -----
load-in swap-out swapped delta used delta used delta
138837 1078936 800402 +800402 807620 +807620 209.50M +209.50M
4277 38011 829802 +29400 837441 +29821 206.47M -3.03M
3347 39508 862619 +32817 870340 +32899 202.96M -3.51M
4445 36943 890646 +28027 897925 +27585 199.92M -3.04M
10391 16902 886783 -3863 894104 -3821 200.22M +309.56K
8888 19507 888371 +1588 895678 +1574 200.05M -171.81K
8377 20082 891664 +3293 899850 +4172 200.10M +53.55K
9671 20210 892586 +922 899917 +67 199.82M -285.30K
10861 16723 887638 -4948 895003 -4914 200.13M +312.35K
9541 21945 890618 +2980 898004 +3001 199.94M -197.11K
9689 17257 888345 -2273 896405 -1599 200.27M +337.77K
10087 18784 886771 -1574 894577 -1828 200.36M +91.60K
9330 19350 887411 +640 894817 +240 200.17M -189.72K
</pre>The above output is about a redis-server with VM enable, around 1 million of keys inside, and a lot of simulated load using the redis-load utility.<br/><br/>As you can see from the output a number of load-in and swap-out operations are happening every second. Note that the first line reports the actual values since the server was started, while the next lines are differences compared to the previous reading.<br/><br/>If you assigned enough memory to hold your working set of data, probably you should see a lot less dramatic swapping happening, so redis-stat can be a really valuable tool in order to understand if you need to shop for RAM ;)<h2><a name="Redis with VM enabled: better .rdb files or Append Only File?">Redis with VM enabled: better .rdb files or Append Only File?</a></h2>When VM is enabled, saving and loading the database are <b>much slower</b> operations. A DB that usually loads in 2 seconds takes 13 seconds with VM enabled if the server is configured to use the smallest memory possible (that is, vm-max-memory set to 0).<br/><br/>So you probably want to switch to a configuration using the Append Only File for persistence, so that you can perform the BGREWRITEAOF from time to time.<br/><br/>It is important to note that while a BGSAVE or BGREWRITEAOF is in progress Redis does <b>not</b> swap new values on disk. The VM will be read-only while there is another child accessing it. So if you have a lot of writes while there is a child working, the memory usage may grow.<h2><a name="Using as little memory as possible">Using as little memory as possible</a></h2>An interesting setup to turn Redis into an on-disk DB with just keys in memory is setting vm-max-memory to 0. If you don't mind some latency more and poorer performances but want to use very little memory for very big values, this is a good setup.<br/><br/>In this setup you should first try setting the VM as blocking (vm-max-threads 0) as with this configuration and high traffic the number of swap in and swap out operations will be huge, and threading will consume a lot of resources compared to a simple blocking implementation.<h2><a name="VM Stability">VM Stability</a></h2>VM is still experimental code, but in the latest weeks it was tested in many ways in development environments, and even in some production environment. No bugs were noticed during this testing period. Still the more obscure bugs may happen in non controlled environments where there are setups that we are not able to reproduce for some reason.<br/><br/>In this stage you are encouraged to try VM in your development environment, and even in production if your DB is not mission critical, but for instance just a big persistent cache of data that may go away without too much problems.<br/><br/>Please report any problem you will notice to the Redis Google Group or by IRC joining the #redis IRC channel on freenode.
</div>
</div>
</div>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<link type="text/css" rel="stylesheet" href="style.css" />
</head>
<body>
<div id="page">
<div id='header'>
<a href="index.html">
<img style="border:none" alt="Redis Documentation" src="redis.png">
</a>
</div>
<div id="pagecontent">
<div class="index">
<!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
<b>ZaddCommand: Contents</b><br>&nbsp;&nbsp;<a href="#ZADD _key_ _score_ _member_ (Redis &gt;">ZADD _key_ _score_ _member_ (Redis &gt;</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Return value">Return value</a>
</div>
<h1 class="wikiname">ZaddCommand</h1>
<div class="summary">
</div>
<div class="narrow">
&iuml;&raquo;&iquest;#sidebar <a href="SortedSetCommandsSidebar.html">SortedSetCommandsSidebar</a><h1><a name="ZADD _key_ _score_ _member_ (Redis &gt;">ZADD _key_ _score_ _member_ (Redis &gt;</a></h1> 1.1) =
<i>Time complexity O(log(N)) with N being the number of elements in the sorted set</i><blockquote>Add the specified <i>member</i> having the specifeid <i>score</i> to the sortedset stored at <i>key</i>. If <i>member</i> is already a member of the sorted setthe score is updated, and the element reinserted in the right position toensure sorting. If <i>key</i> does not exist a new sorted set with the specified_member_ as sole member is crated. If the key exists but does not hold asorted set value an error is returned.</blockquote>
<blockquote>The score value can be the string representation of a double precision floatingpoint number.</blockquote>
<blockquote>For an introduction to sorted sets check the <a href="IntroductionToRedisDataTypes.html">Introduction to Redis data types</a> page.</blockquote>
<h2><a name="Return value">Return value</a></h2><a href="ReplyTypes.html">Integer reply</a>, specifically:<br/><br/><pre class="codeblock python" name="code">
1 if the new element was added
0 if the element was already a member of the sorted set and the score was updated
</pre>
</div>
</div>
</div>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<link type="text/css" rel="stylesheet" href="style.css" />
</head>
<body>
<div id="page">
<div id='header'>
<a href="index.html">
<img style="border:none" alt="Redis Documentation" src="redis.png">
</a>
</div>
<div id="pagecontent">
<div class="index">
<!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
<b>ZcardCommand: Contents</b><br>&nbsp;&nbsp;<a href="#ZCARD _key_ (Redis &gt;">ZCARD _key_ (Redis &gt;</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Return value">Return value</a>
</div>
<h1 class="wikiname">ZcardCommand</h1>
<div class="summary">
</div>
<div class="narrow">
&iuml;&raquo;&iquest;#sidebar <a href="SortedSetCommandsSidebar.html">SortedSetCommandsSidebar</a><h1><a name="ZCARD _key_ (Redis &gt;">ZCARD _key_ (Redis &gt;</a></h1> 1.1) =
<i>Time complexity O(1)</i><blockquote>Return the sorted set cardinality (number of elements). If the <i>key</i> does notexist 0 is returned, like for empty sorted sets.</blockquote>
<h2><a name="Return value">Return value</a></h2><a href="ReplyTypes.html">Integer reply</a>, specifically:<br/><br/><pre class="codeblock python" name="code">
the cardinality (number of elements) of the set as an integer.
</pre>
</div>
</div>
</div>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<link type="text/css" rel="stylesheet" href="style.css" />
</head>
<body>
<div id="page">
<div id='header'>
<a href="index.html">
<img style="border:none" alt="Redis Documentation" src="redis.png">
</a>
</div>
<div id="pagecontent">
<div class="index">
<!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
<b>ZincrbyCommand: Contents</b><br>&nbsp;&nbsp;<a href="#ZINCRBY _key_ _increment_ _member_ (Redis &gt;">ZINCRBY _key_ _increment_ _member_ (Redis &gt;</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Return value">Return value</a>
</div>
<h1 class="wikiname">ZincrbyCommand</h1>
<div class="summary">
</div>
<div class="narrow">
&iuml;&raquo;&iquest;#sidebar <a href="SortedSetCommandsSidebar.html">SortedSetCommandsSidebar</a><h1><a name="ZINCRBY _key_ _increment_ _member_ (Redis &gt;">ZINCRBY _key_ _increment_ _member_ (Redis &gt;</a></h1> 1.1) =
<i>Time complexity O(log(N)) with N being the number of elements in the sorted set</i><blockquote>If <i>member</i> already exists in the sorted set adds the <i>increment</i> to its scoreand updates the position of the element in the sorted set accordingly.If <i>member</i> does not already exist in the sorted set it is added with_increment_ as score (that is, like if the previous score was virtually zero).If <i>key</i> does not exist a new sorted set with the specified_member_ as sole member is crated. If the key exists but does not hold asorted set value an error is returned.</blockquote>
<blockquote>The score value can be the string representation of a double precision floatingpoint number. It's possible to provide a negative value to perform a decrement.</blockquote>
<blockquote>For an introduction to sorted sets check the <a href="IntroductionToRedisDataTypes.html">Introduction to Redis data types</a> page.</blockquote>
<h2><a name="Return value">Return value</a></h2><a href="ReplyTypes.html">Bulk reply</a><pre class="codeblock python" name="code">
The new score (a double precision floating point number) represented as string.
</pre>
</div>
</div>
</div>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<link type="text/css" rel="stylesheet" href="style.css" />
</head>
<body>
<div id="page">
<div id='header'>
<a href="index.html">
<img style="border:none" alt="Redis Documentation" src="redis.png">
</a>
</div>
<div id="pagecontent">
<div class="index">
<!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
<b>ZrangeCommand: Contents</b><br>&nbsp;&nbsp;<a href="#ZRANGE _key_ _start_ _end_ `[`WITHSCORES`]`(Redis &gt;">ZRANGE _key_ _start_ _end_ `[`WITHSCORES`]`(Redis &gt;</a><br>&nbsp;&nbsp;<a href="#ZREVRANGE _key_ _start_ _end_ `[`WITHSCORES`]` (Redis &gt;">ZREVRANGE _key_ _start_ _end_ `[`WITHSCORES`]` (Redis &gt;</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Return value">Return value</a>
</div>
<h1 class="wikiname">ZrangeCommand</h1>
<div class="summary">
</div>
<div class="narrow">
&iuml;&raquo;&iquest;#sidebar <a href="SortedSetCommandsSidebar.html">SortedSetCommandsSidebar</a><h1><a name="ZRANGE _key_ _start_ _end_ `[`WITHSCORES`]`(Redis &gt;">ZRANGE _key_ _start_ _end_ `[`WITHSCORES`]`(Redis &gt;</a></h1> 1.1) =
<h1><a name="ZREVRANGE _key_ _start_ _end_ `[`WITHSCORES`]` (Redis &gt;">ZREVRANGE _key_ _start_ _end_ `[`WITHSCORES`]` (Redis &gt;</a></h1> 1.1) =
<i>Time complexity: O(log(N))+O(M) (with N being the number of elements in the sorted set and M the number of elements requested)</i><blockquote>Return the specified elements of the sorted set at the specifiedkey. The elements are considered sorted from the lowerest to the highestscore when using ZRANGE, and in the reverse order when using ZREVRANGE.Start and end are zero-based indexes. 0 is the first elementof the sorted set (the one with the lowerest score when using ZRANGE), 1the next element by score and so on.</blockquote>
<blockquote>_start_ and <i>end</i> can also be negative numbers indicating offsetsfrom the end of the sorted set. For example -1 is the last element ofthe sorted set, -2 the penultimate element and so on.</blockquote>
<blockquote>Indexes out of range will not produce an error: if start is overthe end of the sorted set, or start <code name="code" class="python">&gt;</code> end, an empty list is returned.If end is over the end of the sorted set Redis will threat it just likethe last element of the sorted set.</blockquote>
<blockquote>It's possible to pass the WITHSCORES option to the command in order to return notonly the values but also the scores of the elements. Redis will return the dataas a single list composed of value1,score1,value2,score2,...,valueN,scoreN but clientlibraries are free to return a more appropriate data type (what we think is thatthe best return type for this command is a Array of two-elements Array / Tuple inorder to preserve sorting).</blockquote>
<h2><a name="Return value">Return value</a></h2><a href="ReplyTypes.html">Multi bulk reply</a>, specifically a list of elements in the specified range.
</div>
</div>
</div>
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
<link type="text/css" rel="stylesheet" href="style.css" />
</head>
<body>
<div id="page">
<div id='header'>
<a href="index.html">
<img style="border:none" alt="Redis Documentation" src="redis.png">
</a>
</div>
<div id="pagecontent">
<div class="index">
<!-- This is a (PRE) block. Make sure it's left aligned or your toc title will be off. -->
<b>ZrangebyscoreCommand: Contents</b><br>&nbsp;&nbsp;<a href="#ZRANGEBYSCORE _key_ _min_ _max_ `[`LIMIT _offset_ _count_`]` (Redis &gt;">ZRANGEBYSCORE _key_ _min_ _max_ `[`LIMIT _offset_ _count_`]` (Redis &gt;</a><br>&nbsp;&nbsp;<a href="#ZRANGEBYSCORE _key_ _min_ _max_ `[`LIMIT _offset_ _count_`]` `[`WITHSCORES`]` (Redis &gt;">ZRANGEBYSCORE _key_ _min_ _max_ `[`LIMIT _offset_ _count_`]` `[`WITHSCORES`]` (Redis &gt;</a><br>&nbsp;&nbsp;<a href="#ZCOUNT _key_ _min_ _max_">ZCOUNT _key_ _min_ _max_</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Exclusive intervals and infinity">Exclusive intervals and infinity</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Return value">Return value</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Examples">Examples</a>
</div>
<h1 class="wikiname">ZrangebyscoreCommand</h1>
<div class="summary">
</div>
<div class="narrow">
&iuml;&raquo;&iquest;#sidebar <a href="SortedSetCommandsSidebar.html">SortedSetCommandsSidebar</a><h1><a name="ZRANGEBYSCORE _key_ _min_ _max_ `[`LIMIT _offset_ _count_`]` (Redis &gt;">ZRANGEBYSCORE _key_ _min_ _max_ `[`LIMIT _offset_ _count_`]` (Redis &gt;</a></h1> 1.1) =
<h1><a name="ZRANGEBYSCORE _key_ _min_ _max_ `[`LIMIT _offset_ _count_`]` `[`WITHSCORES`]` (Redis &gt;">ZRANGEBYSCORE _key_ _min_ _max_ `[`LIMIT _offset_ _count_`]` `[`WITHSCORES`]` (Redis &gt;</a></h1> 1.3.4) =
<h1><a name="ZCOUNT _key_ _min_ _max_">ZCOUNT _key_ _min_ _max_</a></h1>
<i>Time complexity: O(log(N))+O(M) with N being the number of elements in the sorted set and M the number of elements returned by the command, so if M is constant (for instance you always ask for the first ten elements with LIMIT) you can consider it O(log(N))</i><blockquote>Return the all the elements in the sorted set at key with a score between_min_ and <i>max</i> (including elements with score equal to min or max).</blockquote>
<blockquote>The elements having the same score are returned sorted lexicographically asASCII strings (this follows from a property of Redis sorted sets and does notinvolve further computation).</blockquote>
<blockquote>Using the optional LIMIT it's possible to get only a range of the matchingelements in an SQL-alike way. Note that if <i>offset</i> is large the commandsneeds to traverse the list for <i>offset</i> elements and this adds up to theO(M) figure.</blockquote>
<blockquote>The <b>ZCOUNT</b> command is similar to <b>ZRANGEBYSCORE</b> but instead of returningthe actual elements in the specified interval, it just returns the numberof matching elements.</blockquote><h2><a name="Exclusive intervals and infinity">Exclusive intervals and infinity</a></h2>
<i>min</i> and <i>max</i> can be -inf and +inf, so that you are not required to know what's the greatest or smallest element in order to take, for instance, elements &quot;up to a given value&quot;.<br/><br/>Also while the interval is for default closed (inclusive) it's possible to specify open intervals prefixing the score with a &quot;(&quot; character, so for instance:
<pre class="codeblock python" name="code">
ZRANGEBYSCORE zset (1.3 5
</pre>
Will return all the values with score <b>&gt; 1.3 and &lt;= 5</b>, while for instance:
<pre class="codeblock python python" name="code">
ZRANGEBYSCORE zset (5 (10
</pre>
Will return all the values with score <b>&gt; 5 and &lt; 10</b> (5 and 10 excluded).
<h2><a name="Return value">Return value</a></h2>ZRANGEBYSCORE returns a <a href="ReplyTypes.html">Multi bulk reply</a> specifically a list of elements in the specified score range.<br/><br/>ZCOUNT returns a <a href="ReplyTypes.html">Integer reply</a> specifically the number of elements matching the specified score range.
<h2><a name="Examples">Examples</a></h2>
<pre class="codeblock python python python" name="code">
redis&gt; zadd zset 1 foo
(integer) 1
redis&gt; zadd zset 2 bar
(integer) 1
redis&gt; zadd zset 3 biz
(integer) 1
redis&gt; zadd zset 4 foz
(integer) 1
redis&gt; zrangebyscore zset -inf +inf
1. &quot;foo&quot;
2. &quot;bar&quot;
3. &quot;biz&quot;
4. &quot;foz&quot;
redis&gt; zcount zset 1 2
(integer) 2
redis&gt; zrangebyscore zset 1 2
1. &quot;foo&quot;
2. &quot;bar&quot;
redis&gt; zrangebyscore zset (1 2
1. &quot;bar&quot;
redis&gt; zrangebyscore zset (1 (2
(empty list or set)
</pre>
</div>
</div>
</div>
</body>
</html>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment