Commit 0d1650f8 authored by antirez's avatar antirez
Browse files

Updated to unstable

parents 3bb818df 55937b79
<!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>
<!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>ZrankCommand: Contents</b><br>&nbsp;&nbsp;<a href="#ZRANK _key_ _member_ (Redis &gt;">ZRANK _key_ _member_ (Redis &gt;</a><br>&nbsp;&nbsp;<a href="#ZREVRANK _key_ _member_ (Redis &gt;">ZREVRANK _key_ _member_ (Redis &gt;</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Return value">Return value</a>
</div>
<h1 class="wikiname">ZrankCommand</h1>
<div class="summary">
</div>
<div class="narrow">
<h1><a name="ZRANK _key_ _member_ (Redis &gt;">ZRANK _key_ _member_ (Redis &gt;</a></h1> 1.3.4) =
<h1><a name="ZREVRANK _key_ _member_ (Redis &gt;">ZREVRANK _key_ _member_ (Redis &gt;</a></h1> 1.3.4) =
<i>Time complexity: O(log(N))</i><blockquote>ZRANK returns the rank of the member in the sorted set, with scores ordered from low to high. ZREVRANK returns the rank with scores ordered from high to low. When the given member does not exist in the sorted set, the special value 'nil' is returned. The returned rank (or index) of the member is 0-based for both commands.</blockquote>
<h2><a name="Return value">Return value</a></h2><a href="ReplyTypes.html">Integer reply</a> or a nil <a href="ReplyTypes.html">bulk reply</a>, specifically:<br/><br/><pre class="codeblock python" name="code">
the rank of the element as an integer reply if the element exists.
A nil bulk reply if there is no such element.
</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>ZremCommand: Contents</b><br>&nbsp;&nbsp;<a href="#ZREM _key_ _member_ (Redis &gt;">ZREM _key_ _member_ (Redis &gt;</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Return value">Return value</a>
</div>
<h1 class="wikiname">ZremCommand</h1>
<div class="summary">
</div>
<div class="narrow">
&iuml;&raquo;&iquest;#sidebar <a href="SortedSetCommandsSidebar.html">SortedSetCommandsSidebar</a><h1><a name="ZREM _key_ _member_ (Redis &gt;">ZREM _key_ _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>Remove the specified <i>member</i> from the sorted set value stored at <i>key</i>. If_member_ was not a member of the set no operation is performed. If <i>key</i>does not not hold a set value an error is returned.</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 removed
0 if the new element was not a member of the set
</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>ZremrangebyrankCommand: Contents</b><br>&nbsp;&nbsp;<a href="#ZREMRANGEBYRANK _key_ _start_ _end_ (Redis &gt;">ZREMRANGEBYRANK _key_ _start_ _end_ (Redis &gt;</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Return value">Return value</a>
</div>
<h1 class="wikiname">ZremrangebyrankCommand</h1>
<div class="summary">
</div>
<div class="narrow">
<h1><a name="ZREMRANGEBYRANK _key_ _start_ _end_ (Redis &gt;">ZREMRANGEBYRANK _key_ _start_ _end_ (Redis &gt;</a></h1> 1.3.4) =
<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 removed by the operation</i><blockquote>Remove all elements in the sorted set at <i>key</i> with rank between <i>start</i> and <i>end</i>. Start and end are 0-based with rank 0 being the element with the lowest score. Both start and end can be negative numbers, where they indicate offsets starting at the element with the highest rank. For example: -1 is the element with the highest score, -2 the element with the second highest score and so forth.</blockquote>
<h2><a name="Return value">Return value</a></h2><a href="ReplyTypes.html">Integer reply</a>, specifically the number of elements removed.
</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>ZremrangebyscoreCommand: Contents</b><br>&nbsp;&nbsp;<a href="#ZREMRANGEBYSCORE _key_ _min_ _max_ (Redis &gt;">ZREMRANGEBYSCORE _key_ _min_ _max_ (Redis &gt;</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Return value">Return value</a>
</div>
<h1 class="wikiname">ZremrangebyscoreCommand</h1>
<div class="summary">
</div>
<div class="narrow">
&iuml;&raquo;&iquest;#sidebar <a href="SortedSetCommandsSidebar.html">SortedSetCommandsSidebar</a><h1><a name="ZREMRANGEBYSCORE _key_ _min_ _max_ (Redis &gt;">ZREMRANGEBYSCORE _key_ _min_ _max_ (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 removed by the operation</i><blockquote>Remove 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>
<h2><a name="Return value">Return value</a></h2><a href="ReplyTypes.html">Integer reply</a>, specifically the number of elements removed.
</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>ZscoreCommand: Contents</b><br>&nbsp;&nbsp;<a href="#ZSCORE _key_ _element_ (Redis &gt;">ZSCORE _key_ _element_ (Redis &gt;</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Return value">Return value</a>
</div>
<h1 class="wikiname">ZscoreCommand</h1>
<div class="summary">
</div>
<div class="narrow">
&iuml;&raquo;&iquest;#sidebar <a href="SortedSetCommandsSidebar.html">SortedSetCommandsSidebar</a><h1><a name="ZSCORE _key_ _element_ (Redis &gt;">ZSCORE _key_ _element_ (Redis &gt;</a></h1> 1.1) =
<i>Time complexity O(1)</i><blockquote>Return the score of the specified element of the sorted set at key.If the specified element does not exist in the sorted set, or the keydoes not exist at all, a special 'nil' value is returned.</blockquote>
<h2><a name="Return value">Return value</a></h2><a href="ReplyTypes.html">Bulk reply</a><pre class="codeblock python" name="code">
the 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>ZunionCommand: Contents</b><br>&nbsp;&nbsp;<a href="#ZUNIONSTORE _dstkey_ _N_ _k1_ ... _kN_ `[`WEIGHTS _w1_ ... _wN_`]` `[`AGGREGATE SUM|MIN|MAX`]` (Redis &gt;">ZUNIONSTORE _dstkey_ _N_ _k1_ ... _kN_ `[`WEIGHTS _w1_ ... _wN_`]` `[`AGGREGATE SUM|MIN|MAX`]` (Redis &gt;</a><br>&nbsp;&nbsp;<a href="#ZINTERSTORE _dstkey_ _N_ _k1_ ... _kN_ `[`WEIGHTS _w1_ ... _wN_`]` `[`AGGREGATE SUM|MIN|MAX`]` (Redis &gt;">ZINTERSTORE _dstkey_ _N_ _k1_ ... _kN_ `[`WEIGHTS _w1_ ... _wN_`]` `[`AGGREGATE SUM|MIN|MAX`]` (Redis &gt;</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Return value">Return value</a>
</div>
<h1 class="wikiname">ZunionCommand</h1>
<div class="summary">
</div>
<div class="narrow">
<h1><a name="ZUNIONSTORE _dstkey_ _N_ _k1_ ... _kN_ `[`WEIGHTS _w1_ ... _wN_`]` `[`AGGREGATE SUM|MIN|MAX`]` (Redis &gt;">ZUNIONSTORE _dstkey_ _N_ _k1_ ... _kN_ `[`WEIGHTS _w1_ ... _wN_`]` `[`AGGREGATE SUM|MIN|MAX`]` (Redis &gt;</a></h1> 1.3.12) =
<h1><a name="ZINTERSTORE _dstkey_ _N_ _k1_ ... _kN_ `[`WEIGHTS _w1_ ... _wN_`]` `[`AGGREGATE SUM|MIN|MAX`]` (Redis &gt;">ZINTERSTORE _dstkey_ _N_ _k1_ ... _kN_ `[`WEIGHTS _w1_ ... _wN_`]` `[`AGGREGATE SUM|MIN|MAX`]` (Redis &gt;</a></h1> 1.3.12) =<br/><br/><i>Time complexity: O(N) + O(M log(M)) with N being the sum of the sizes of the input sorted sets, and M being the number of elements in the resulting sorted set</i><blockquote>Creates a union or intersection of <i>N</i> sorted sets given by keys <i>k1</i> through <i>kN</i>, and stores it at <i>dstkey</i>. It is mandatory to provide the number of input keys <i>N</i>, before passing the input keys and the other (optional) arguments.</blockquote>
<blockquote>As the terms imply, the ZINTERSTORE command requires an element to be present in each of the given inputs to be inserted in the result. The ZUNIONSTORE command inserts all elements across all inputs.</blockquote>
<blockquote>Using the WEIGHTS option, it is possible to add weight to each input sorted set. This means that the score of each element in the sorted set is first multiplied by this weight before being passed to the aggregation. When this option is not given, all weights default to 1.</blockquote>
<blockquote>With the AGGREGATE option, it's possible to specify how the results of the union or intersection are aggregated. This option defaults to SUM, where the score of an element is summed across the inputs where it exists. When this option is set to be either MIN or MAX, the resulting set will contain the minimum or maximum score of an element across the inputs where it exists.</blockquote>
<h2><a name="Return value">Return value</a></h2><a href="ReplyTypes.html">Integer reply</a>, specifically the number of elements in the sorted set at <i>dstkey</i>.
</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>ZunionstoreCommand: Contents</b><br>&nbsp;&nbsp;<a href="#ZUNIONSTORE _dstkey_ _N_ _k1_ ... _kN_ `[`WEIGHTS _w1_ ... _wN_`]` `[`AGGREGATE SUM|MIN|MAX`]` (Redis &gt;">ZUNIONSTORE _dstkey_ _N_ _k1_ ... _kN_ `[`WEIGHTS _w1_ ... _wN_`]` `[`AGGREGATE SUM|MIN|MAX`]` (Redis &gt;</a><br>&nbsp;&nbsp;<a href="#ZINTERSTORE _dstkey_ _N_ _k1_ ... _kN_ `[`WEIGHTS _w1_ ... _wN_`]` `[`AGGREGATE SUM|MIN|MAX`]` (Redis &gt;">ZINTERSTORE _dstkey_ _N_ _k1_ ... _kN_ `[`WEIGHTS _w1_ ... _wN_`]` `[`AGGREGATE SUM|MIN|MAX`]` (Redis &gt;</a><br>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#Return value">Return value</a>
</div>
<h1 class="wikiname">ZunionstoreCommand</h1>
<div class="summary">
</div>
<div class="narrow">
<h1><a name="ZUNIONSTORE _dstkey_ _N_ _k1_ ... _kN_ `[`WEIGHTS _w1_ ... _wN_`]` `[`AGGREGATE SUM|MIN|MAX`]` (Redis &gt;">ZUNIONSTORE _dstkey_ _N_ _k1_ ... _kN_ `[`WEIGHTS _w1_ ... _wN_`]` `[`AGGREGATE SUM|MIN|MAX`]` (Redis &gt;</a></h1> 1.3.12) =
<h1><a name="ZINTERSTORE _dstkey_ _N_ _k1_ ... _kN_ `[`WEIGHTS _w1_ ... _wN_`]` `[`AGGREGATE SUM|MIN|MAX`]` (Redis &gt;">ZINTERSTORE _dstkey_ _N_ _k1_ ... _kN_ `[`WEIGHTS _w1_ ... _wN_`]` `[`AGGREGATE SUM|MIN|MAX`]` (Redis &gt;</a></h1> 1.3.12) =
<i>Time complexity: O(N) + O(M log(M)) with N being the sum of the sizes of the input sorted sets, and M being the number of elements in the resulting sorted set</i><blockquote>Creates a union or intersection of <i>N</i> sorted sets given by keys <i>k1</i> through <i>kN</i>, and stores it at <i>dstkey</i>. It is mandatory to provide the number of input keys <i>N</i>, before passing the input keys and the other (optional) arguments.</blockquote>
<blockquote>As the terms imply, the ZINTERSTORE command requires an element to be present in each of the given inputs to be inserted in the result. The ZUNIONSTORE command inserts all elements across all inputs.</blockquote>
<blockquote>Using the WEIGHTS option, it is possible to add weight to each input sorted set. This means that the score of each element in the sorted set is first multiplied by this weight before being passed to the aggregation. When this option is not given, all weights default to 1.</blockquote>
<blockquote>With the AGGREGATE option, it's possible to specify how the results of the union or intersection are aggregated. This option defaults to SUM, where the score of an element is summed across the inputs where it exists. When this option is set to be either MIN or MAX, the resulting set will contain the minimum or maximum score of an element across the inputs where it exists.</blockquote>
<h2><a name="Return value">Return value</a></h2><a href="ReplyTypes.html">Integer reply</a>, specifically the number of elements in the sorted set at <i>dstkey</i>.
</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>index: Contents</b><br>&nbsp;&nbsp;<a href="#Getting started">Getting started</a><br>&nbsp;&nbsp;<a href="#Full programming examples">Full programming examples</a><br>&nbsp;&nbsp;<a href="#FAQs and benchmarks">FAQs and benchmarks</a><br>&nbsp;&nbsp;<a href="#HOWTOs about selected features">HOWTOs about selected features</a><br>&nbsp;&nbsp;<a href="#Hacking">Hacking</a><br>&nbsp;&nbsp;<a href="#Videos">Videos</a><br>&nbsp;&nbsp;<a href="#Recipes and books">Recipes and books</a>
</div>
<h1 class="wikiname">index</h1>
<div class="summary">
</div>
<div class="narrow">
&iuml;&raquo;&iquest;= Redis Documentation =<br/><br/><a href="http://pyha.ru/wiki/index.php?title=Redis:index" target="_blank">Russian Translation</a>Hello! The followings are pointers to different parts of the Redis Documentation.<h1><a name="Getting started">Getting started</a></h1><ul><li> New! You can now <a href="http://try.redis-db.com" target="_blank">Try Redis directly in your browser!</a>.</li><li> <a href="README.html">The README</a> is a good starting point to know more about the project.</li><li> <a href="QuickStart.html">This short Quick Start</a> provides a five minutes step-by-step istructions on how to download, compile, run and test the basic workings of a Redis server.</li><li> <a href="CommandReference.html">The command reference</a> is a description of all the Redis commands with links to command specific pages. You can also download the <a href="http://go2.wordpress.com/?id=725X1342&site=masonoise.wordpress.com&url=http%3A%2F%2Fmasonoise.files.wordpress.com%2F2010%2F03%2Fredis-cheatsheet-v1.pdf" target="_blank">Redis Commands Cheat-Sheet</a> provided by Mason Jones (btw some command may be missing, the primary source is the wiki).</li><li> <a href="IntroductionToRedisDataTypes.html">A Fifteen Minutes Introduction to the Redis Data Types</a> explains how Redis data types work and the basic patterns of working with Redis.</li><li> <a href="http://simonwillison.net/static/2010/redis-tutorial/" target="_blank">the Simon Willison Redis Tutorial</a> is a <b>must read</b>, very good documentation where you will find a lot of real world ideas and use cases.</li><li> <a href="http://blog.mjrusso.com/2010/10/17/redis-from-the-ground-up.html" target="_blank">Redis from the ground up</a> is an impressive article to know more about Redis if you are a newcomer.</li><li> <a href="http://playnice.ly/blog/2010/10/19/getting-started-redis-python/" target="_blank">Getting started with Redis and Python</a></li></ul>
<h1><a name="Full programming examples">Full programming examples</a></h1><ul><li> <a href="TwitterAlikeExample.html">This is a tutorial about creating a Twitter clone using *only* Redis as database, no relational DB at all is used</a>, it is a good start to understand the key-value database paradigm.</li></ul>
<h1><a name="FAQs and benchmarks">FAQs and benchmarks</a></h1><ul><li> <a href="Benchmarks.html">The benchmark page</a> is about the speed performances of Redis.</li><li> <a href="FAQ.html">Our FAQ</a> contains of course some answers to common questions about Redis. Not very up-to-date.</li></ul>
<h1><a name="HOWTOs about selected features">HOWTOs about selected features</a></h1><ul><li> <a href="ReplicationHowto.html">The Redis Replication HOWTO</a> is what you need to read in order to understand how Redis master <code name="code" class="python">&lt;-&gt;</code> slave replication works.</li><li> <a href="AppendOnlyFileHowto.html">The Append Only File HOWTO</a> explains how the alternative Redis durability mode works. AOF is an alternative to snapshotting on disk from time to time (the default).</li><li> <a href="VirtualMemoryUserGuide.html">Virtual Memory User Guide</a>. A simple to understand guide about using and configuring the Redis Virtual Memory.</li><li> <a href="RedisPipelining.html">Redis Pipelining Guide</a>.</li><li> Memory optimization: Full of keys, a <a href="http://antirez.com/post/redis-weekly-update-7.html" target="_blank">blog post at antirez.com</a> showing how to use Redis 2.0 and hashes to create a setup where you can store 5 times more data in your Redis instance.</li><li> <a href="http://antirez.com/post/autocomplete-with-redis.html" target="_blank">Implementing auto complete with Redis</a>.</li></ul>
<h1><a name="Hacking">Hacking</a></h1>
<ul><li> <a href="ProtocolSpecification.html">The Protocol Specification</a> is all you need in order to implement a Redis client library for a missing language. PHP, Python, Ruby and Erlang are already supported.</li><li> Look at <a href="RedisInternals.html">Redis Internals</a> if you are interested in the implementation details of the Redis server.</li></ul>
<h1><a name="Videos">Videos</a></h1><ul><li> <a href="http://confreaks.net/videos/62-mwrc2009-redis-key-value-nirvana" target="_blank">Ezra Zygmuntowicz at the Mountain West Ruby Conference 2009</a> to know the most important Redis ideas in few minutes.</li><li> <a href="http://www.ustream.tv/recorded/7855635" target="_blank">Salvatore Sanfilippo and Pieter Noordhuis at the SF Redis Meetup</a></li></ul>
<h1><a name="Recipes and books">Recipes and books</a></h1><ul><li> <a href="http://www.rediscookbook.org/" target="_blank">The Redis Cookbook</a> is a collaborative effort to provide some good recipe.</li><li> There is an ongoing effort to write a Redis book for O'Reilly</li></ul>
</div>
</div>
</div>
</body>
</html>
body {
font-family: 'Verdana';
width:800px;
}
a {
text-decoration: none;
}
h1, h2, h3, h4, h5 {
color: #333;
}
h1 {
font-size: 20px;
}
.codeblock {
color: darkgreen;
padding:5px;
}
h1.wikiname {
color: #f55000;
}
...@@ -292,6 +292,26 @@ appendfsync everysec ...@@ -292,6 +292,26 @@ appendfsync everysec
# "no" that is the safest pick from the point of view of durability. # "no" that is the safest pick from the point of view of durability.
no-appendfsync-on-rewrite no no-appendfsync-on-rewrite no
# Automatic rewrite of the append only file.
# Redis is able to automatically rewrite the log file implicitly calling
# BGREWRITEAOF when the AOF log size will growth by the specified percentage.
#
# This is how it works: Redis remembers the size of the AOF file after the
# latest rewrite (or if no rewrite happened since the restart, the size of
# the AOF at startup is used).
#
# This base size is compared to the current size. If the current size is
# bigger than the specified percentage, the rewrite is triggered. Also
# you need to specify a minimal size for the AOF file to be rewritten, this
# is useful to avoid rewriting the AOF file even if the percentage increase
# is reached but it is still pretty small.
#
# Specify a precentage of zero in order to disable the automatic AOF
# rewrite feature.
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
################################ LUA SCRIPTING ############################### ################################ LUA SCRIPTING ###############################
# Max execution time of a Lua script in milliseconds. # Max execution time of a Lua script in milliseconds.
......
...@@ -46,6 +46,11 @@ BINCOLOR="\033[37;1m" ...@@ -46,6 +46,11 @@ BINCOLOR="\033[37;1m"
MAKECOLOR="\033[32;1m" MAKECOLOR="\033[32;1m"
ENDCOLOR="\033[0m" ENDCOLOR="\033[0m"
ifndef V
QUIET_CC = @printf ' %b %b\n' $(CCCOLOR)CC$(ENDCOLOR) $(SRCCOLOR)$@$(ENDCOLOR);
QUIET_LINK = @printf ' %b %b\n' $(LINKCOLOR)LINK$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR);
endif
OBJ = adlist.o ae.o anet.o dict.o redis.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o dscache.o pubsub.o multi.o debug.o sort.o intset.o syncio.o diskstore.o cluster.o crc16.o endian.o scripting.o OBJ = adlist.o ae.o anet.o dict.o redis.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o dscache.o pubsub.o multi.o debug.o sort.o intset.o syncio.o diskstore.o cluster.o crc16.o endian.o scripting.o
BENCHOBJ = ae.o anet.o redis-benchmark.o sds.o adlist.o zmalloc.o BENCHOBJ = ae.o anet.o redis-benchmark.o sds.o adlist.o zmalloc.o
CLIOBJ = anet.o sds.o adlist.o redis-cli.o zmalloc.o release.o CLIOBJ = anet.o sds.o adlist.o redis-cli.o zmalloc.o release.o
...@@ -132,45 +137,37 @@ zipmap.o: zipmap.c zmalloc.h ...@@ -132,45 +137,37 @@ zipmap.o: zipmap.c zmalloc.h
zmalloc.o: zmalloc.c config.h zmalloc.o: zmalloc.c config.h
dependencies: dependencies:
@echo $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)hiredis$(ENDCOLOR) @printf '%b %b\n' $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)hiredis$(ENDCOLOR)
@cd ../deps/hiredis && $(MAKE) static ARCH="$(ARCH)" @cd ../deps/hiredis && $(MAKE) static ARCH="$(ARCH)"
@echo $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)linenoise$(ENDCOLOR) @printf '%b %b\n' $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)linenoise$(ENDCOLOR)
@cd ../deps/linenoise && $(MAKE) ARCH="$(ARCH)" @cd ../deps/linenoise && $(MAKE) ARCH="$(ARCH)"
@echo $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)Lua ansi$(ENDCOLOR) @echo $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)Lua ansi$(ENDCOLOR)
@cd ../deps/lua && $(MAKE) ARCH="$(ARCH)" ansi @cd ../deps/lua && $(MAKE) ARCH="$(ARCH)" ansi
redis-server: $(OBJ) redis-server: $(OBJ)
@$(CC) -o $(PRGNAME) $(CCOPT) $(DEBUG) $(OBJ) ../deps/lua/src/liblua.a $(QUIET_CC)$(CC) -o $(PRGNAME) $(CCOPT) $(DEBUG) $(OBJ) ../deps/lua/src/liblua.a
@echo $(LINKCOLOR)LINK$(ENDCOLOR) $(BINCOLOR)$(@)$(ENDCOLOR)
redis-benchmark: dependencies $(BENCHOBJ) redis-benchmark: dependencies $(BENCHOBJ)
@cd ../deps/hiredis && $(MAKE) static @cd ../deps/hiredis && $(MAKE) static
@$(CC) -o $(BENCHPRGNAME) $(CCOPT) $(DEBUG) $(BENCHOBJ) ../deps/hiredis/libhiredis.a $(QUIET_LINK)$(CC) -o $(BENCHPRGNAME) $(CCOPT) $(DEBUG) $(BENCHOBJ) ../deps/hiredis/libhiredis.a
@echo $(LINKCOLOR)LINK$(ENDCOLOR) $(BINCOLOR)$(@)$(ENDCOLOR)
redis-benchmark.o: redis-benchmark.o:
@$(CC) -c $(CFLAGS) -I../deps/hiredis $(DEBUG) $(COMPILE_TIME) $< $(QUIET_CC)$(CC) -c $(CFLAGS) -I../deps/hiredis $(DEBUG) $(COMPILE_TIME) $<
@echo $(CCCOLOR)CC$(ENDCOLOR) $(SRCCOLOR)$(<)$(ENDCOLOR)
redis-cli: dependencies $(CLIOBJ) redis-cli: dependencies $(CLIOBJ)
@$(CC) -o $(CLIPRGNAME) $(CCOPT) $(DEBUG) $(CLIOBJ) ../deps/hiredis/libhiredis.a ../deps/linenoise/linenoise.o $(QUIET_LINK)$(CC) -o $(CLIPRGNAME) $(CCOPT) $(DEBUG) $(CLIOBJ) ../deps/hiredis/libhiredis.a ../deps/linenoise/linenoise.o
@echo $(LINKCOLOR)LINK$(ENDCOLOR) $(BINCOLOR)$(@)$(ENDCOLOR)
redis-cli.o: redis-cli.o:
@$(CC) -c $(CFLAGS) -I../deps/hiredis -I../deps/linenoise $(DEBUG) $(COMPILE_TIME) $< $(QUIET_CC)$(CC) -c $(CFLAGS) -I../deps/hiredis -I../deps/linenoise $(DEBUG) $(COMPILE_TIME) $<
@echo $(CCCOLOR)CC$(ENDCOLOR) $(SRCCOLOR)$(<)$(ENDCOLOR)
redis-check-dump: $(CHECKDUMPOBJ) redis-check-dump: $(CHECKDUMPOBJ)
@$(CC) -o $(CHECKDUMPPRGNAME) $(CCOPT) $(DEBUG) $(CHECKDUMPOBJ) $(QUIET_LINK)$(CC) -o $(CHECKDUMPPRGNAME) $(CCOPT) $(DEBUG) $(CHECKDUMPOBJ)
@echo $(LINKCOLOR)LINK$(ENDCOLOR) $(BINCOLOR)$(@)$(ENDCOLOR)
redis-check-aof: $(CHECKAOFOBJ) redis-check-aof: $(CHECKAOFOBJ)
@$(CC) -o $(CHECKAOFPRGNAME) $(CCOPT) $(DEBUG) $(CHECKAOFOBJ) $(QUIET_LINK)$(CC) -o $(CHECKAOFPRGNAME) $(CCOPT) $(DEBUG) $(CHECKAOFOBJ)
@echo $(LINKCOLOR)LINK$(ENDCOLOR) $(BINCOLOR)$(@)$(ENDCOLOR)
.c.o: .c.o:
@$(CC) -c $(CFLAGS) $(DEBUG) $(COMPILE_TIME) -I../deps/lua/src $< $(QUIET_CC)$(CC) -c $(CFLAGS) $(DEBUG) $(COMPILE_TIME) -I../deps/lua/src $<
@echo $(CCCOLOR)CC$(ENDCOLOR) $(SRCCOLOR)$(<)$(ENDCOLOR)
clean: clean:
rm -rf $(PRGNAME) $(BENCHPRGNAME) $(CLIPRGNAME) $(CHECKDUMPPRGNAME) $(CHECKAOFPRGNAME) *.o *.gcda *.gcno *.gcov rm -rf $(PRGNAME) $(BENCHPRGNAME) $(CLIPRGNAME) $(CHECKDUMPPRGNAME) $(CHECKAOFPRGNAME) *.o *.gcda *.gcno *.gcov
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
#include <sys/resource.h> #include <sys/resource.h>
#include <sys/wait.h> #include <sys/wait.h>
void aofUpdateCurrentSize(void);
/* Called when the user switches from "appendonly yes" to "appendonly no" /* Called when the user switches from "appendonly yes" to "appendonly no"
* at runtime using the CONFIG command. */ * at runtime using the CONFIG command. */
void stopAppendOnly(void) { void stopAppendOnly(void) {
...@@ -19,15 +21,15 @@ void stopAppendOnly(void) { ...@@ -19,15 +21,15 @@ void stopAppendOnly(void) {
server.appendseldb = -1; server.appendseldb = -1;
server.appendonly = 0; server.appendonly = 0;
/* rewrite operation in progress? kill it, wait child exit */ /* rewrite operation in progress? kill it, wait child exit */
if (server.bgsavechildpid != -1) { if (server.bgrewritechildpid != -1) {
int statloc; int statloc;
if (kill(server.bgsavechildpid,SIGKILL) != -1) if (kill(server.bgrewritechildpid,SIGKILL) != -1)
wait3(&statloc,0,NULL); wait3(&statloc,0,NULL);
/* reset the buffer accumulating changes while the child saves */ /* reset the buffer accumulating changes while the child saves */
sdsfree(server.bgrewritebuf); sdsfree(server.bgrewritebuf);
server.bgrewritebuf = sdsempty(); server.bgrewritebuf = sdsempty();
server.bgsavechildpid = -1; server.bgrewritechildpid = -1;
} }
} }
...@@ -82,6 +84,7 @@ void flushAppendOnlyFile(void) { ...@@ -82,6 +84,7 @@ void flushAppendOnlyFile(void) {
} }
sdsfree(server.aofbuf); sdsfree(server.aofbuf);
server.aofbuf = sdsempty(); server.aofbuf = sdsempty();
server.appendonly_current_size += nwritten;
/* Don't Fsync if no-appendfsync-on-rewrite is set to yes and we have /* Don't Fsync if no-appendfsync-on-rewrite is set to yes and we have
* childs performing heavy I/O on disk. */ * childs performing heavy I/O on disk. */
...@@ -221,6 +224,7 @@ int loadAppendOnlyFile(char *filename) { ...@@ -221,6 +224,7 @@ int loadAppendOnlyFile(char *filename) {
long loops = 0; long loops = 0;
if (fp && redis_fstat(fileno(fp),&sb) != -1 && sb.st_size == 0) { if (fp && redis_fstat(fileno(fp),&sb) != -1 && sb.st_size == 0) {
server.appendonly_current_size = 0;
fclose(fp); fclose(fp);
return REDIS_ERR; return REDIS_ERR;
} }
...@@ -299,6 +303,8 @@ int loadAppendOnlyFile(char *filename) { ...@@ -299,6 +303,8 @@ int loadAppendOnlyFile(char *filename) {
freeFakeClient(fakeClient); freeFakeClient(fakeClient);
server.appendonly = appendonly; server.appendonly = appendonly;
stopLoading(); stopLoading();
aofUpdateCurrentSize();
server.auto_aofrewrite_base_size = server.appendonly_current_size;
return REDIS_OK; return REDIS_OK;
readerr: readerr:
...@@ -565,16 +571,18 @@ werr: ...@@ -565,16 +571,18 @@ werr:
*/ */
int rewriteAppendOnlyFileBackground(void) { int rewriteAppendOnlyFileBackground(void) {
pid_t childpid; pid_t childpid;
long long start;
if (server.bgrewritechildpid != -1) return REDIS_ERR; if (server.bgrewritechildpid != -1) return REDIS_ERR;
if (server.ds_enabled != 0) { if (server.ds_enabled != 0) {
redisLog(REDIS_WARNING,"BGREWRITEAOF called with diskstore enabled: AOF is not supported when diskstore is enabled. Operation not performed."); redisLog(REDIS_WARNING,"BGREWRITEAOF called with diskstore enabled: AOF is not supported when diskstore is enabled. Operation not performed.");
return REDIS_ERR; return REDIS_ERR;
} }
start = ustime();
if ((childpid = fork()) == 0) { if ((childpid = fork()) == 0) {
/* Child */
char tmpfile[256]; char tmpfile[256];
/* Child */
if (server.ipfd > 0) close(server.ipfd); if (server.ipfd > 0) close(server.ipfd);
if (server.sofd > 0) close(server.sofd); if (server.sofd > 0) close(server.sofd);
snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", (int) getpid()); snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", (int) getpid());
...@@ -585,6 +593,7 @@ int rewriteAppendOnlyFileBackground(void) { ...@@ -585,6 +593,7 @@ int rewriteAppendOnlyFileBackground(void) {
} }
} else { } else {
/* Parent */ /* Parent */
server.stat_fork_time = ustime()-start;
if (childpid == -1) { if (childpid == -1) {
redisLog(REDIS_WARNING, redisLog(REDIS_WARNING,
"Can't rewrite append only file in background: fork: %s", "Can't rewrite append only file in background: fork: %s",
...@@ -608,9 +617,10 @@ int rewriteAppendOnlyFileBackground(void) { ...@@ -608,9 +617,10 @@ int rewriteAppendOnlyFileBackground(void) {
void bgrewriteaofCommand(redisClient *c) { void bgrewriteaofCommand(redisClient *c) {
if (server.bgrewritechildpid != -1) { if (server.bgrewritechildpid != -1) {
addReplyError(c,"Background append only file rewriting already in progress"); addReplyError(c,"Background append only file rewriting already in progress");
return; } else if (server.bgsavechildpid != -1) {
} server.aofrewrite_scheduled = 1;
if (rewriteAppendOnlyFileBackground() == REDIS_OK) { addReplyStatus(c,"Background append only file rewriting scheduled");
} else if (rewriteAppendOnlyFileBackground() == REDIS_OK) {
addReplyStatus(c,"Background append only file rewriting started"); addReplyStatus(c,"Background append only file rewriting started");
} else { } else {
addReply(c,shared.err); addReply(c,shared.err);
...@@ -624,6 +634,21 @@ void aofRemoveTempFile(pid_t childpid) { ...@@ -624,6 +634,21 @@ void aofRemoveTempFile(pid_t childpid) {
unlink(tmpfile); unlink(tmpfile);
} }
/* Update the server.appendonly_current_size filed explicitly using stat(2)
* to check the size of the file. This is useful after a rewrite or after
* a restart, normally the size is updated just adding the write length
* to the current lenght, that is much faster. */
void aofUpdateCurrentSize(void) {
struct redis_stat sb;
if (redis_fstat(server.appendfd,&sb) == -1) {
redisLog(REDIS_WARNING,"Unable to check the AOF length: %s",
strerror(errno));
} else {
server.appendonly_current_size = sb.st_size;
}
}
/* A background append only file rewriting (BGREWRITEAOF) terminated its work. /* A background append only file rewriting (BGREWRITEAOF) terminated its work.
* Handle this. */ * Handle this. */
void backgroundRewriteDoneHandler(int exitcode, int bysignal) { void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
...@@ -664,6 +689,8 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) { ...@@ -664,6 +689,8 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
if (server.appendfsync != APPENDFSYNC_NO) aof_fsync(fd); if (server.appendfsync != APPENDFSYNC_NO) aof_fsync(fd);
server.appendseldb = -1; /* Make sure it will issue SELECT */ server.appendseldb = -1; /* Make sure it will issue SELECT */
redisLog(REDIS_NOTICE,"The new append only file was selected for future appends."); redisLog(REDIS_NOTICE,"The new append only file was selected for future appends.");
aofUpdateCurrentSize();
server.auto_aofrewrite_base_size = server.appendonly_current_size;
} else { } else {
/* If append only is disabled we just generate a dump in this /* If append only is disabled we just generate a dump in this
* format. Why not? */ * format. Why not? */
......
...@@ -231,6 +231,18 @@ void loadServerConfig(char *filename) { ...@@ -231,6 +231,18 @@ void loadServerConfig(char *filename) {
err = "argument must be 'no', 'always' or 'everysec'"; err = "argument must be 'no', 'always' or 'everysec'";
goto loaderr; goto loaderr;
} }
} else if (!strcasecmp(argv[0],"auto-aof-rewrite-percentage") &&
argc == 2)
{
server.auto_aofrewrite_perc = atoi(argv[1]);
if (server.auto_aofrewrite_perc < 0) {
err = "Invalid negative percentage for AOF auto rewrite";
goto loaderr;
}
} else if (!strcasecmp(argv[0],"auto-aof-rewrite-min-size") &&
argc == 2)
{
server.auto_aofrewrite_min_size = memtoll(argv[1],NULL);
} else if (!strcasecmp(argv[0],"requirepass") && argc == 2) { } else if (!strcasecmp(argv[0],"requirepass") && argc == 2) {
server.requirepass = zstrdup(argv[1]); server.requirepass = zstrdup(argv[1]);
} else if (!strcasecmp(argv[0],"pidfile") && argc == 2) { } else if (!strcasecmp(argv[0],"pidfile") && argc == 2) {
...@@ -397,6 +409,12 @@ void configSetCommand(redisClient *c) { ...@@ -397,6 +409,12 @@ void configSetCommand(redisClient *c) {
} }
} }
} }
} else if (!strcasecmp(c->argv[2]->ptr,"auto-aof-rewrite-percentage")) {
if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
server.auto_aofrewrite_perc = ll;
} else if (!strcasecmp(c->argv[2]->ptr,"auto-aof-rewrite-min-size")) {
if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
server.auto_aofrewrite_min_size = ll;
} else if (!strcasecmp(c->argv[2]->ptr,"save")) { } else if (!strcasecmp(c->argv[2]->ptr,"save")) {
int vlen, j; int vlen, j;
sds *v = sdssplitlen(o->ptr,sdslen(o->ptr)," ",1,&vlen); sds *v = sdssplitlen(o->ptr,sdslen(o->ptr)," ",1,&vlen);
...@@ -586,6 +604,16 @@ void configGetCommand(redisClient *c) { ...@@ -586,6 +604,16 @@ void configGetCommand(redisClient *c) {
sdsfree(buf); sdsfree(buf);
matches++; matches++;
} }
if (stringmatch(pattern,"auto-aof-rewrite-percentage",0)) {
addReplyBulkCString(c,"auto-aof-rewrite-percentage");
addReplyBulkLongLong(c,server.auto_aofrewrite_perc);
matches++;
}
if (stringmatch(pattern,"auto-aof-rewrite-min-size",0)) {
addReplyBulkCString(c,"auto-aof-rewrite-min-size");
addReplyBulkLongLong(c,server.auto_aofrewrite_min_size);
matches++;
}
if (stringmatch(pattern,"slave-serve-stale-data",0)) { if (stringmatch(pattern,"slave-serve-stale-data",0)) {
addReplyBulkCString(c,"slave-serve-stale-data"); addReplyBulkCString(c,"slave-serve-stale-data");
addReplyBulkCString(c,server.repl_serve_stale_data ? "yes" : "no"); addReplyBulkCString(c,server.repl_serve_stale_data ? "yes" : "no");
......
...@@ -180,7 +180,7 @@ void decrRefCount(void *obj) { ...@@ -180,7 +180,7 @@ void decrRefCount(void *obj) {
robj *o = obj; robj *o = obj;
if (o->refcount <= 0) redisPanic("decrRefCount against refcount <= 0"); if (o->refcount <= 0) redisPanic("decrRefCount against refcount <= 0");
if (--(o->refcount) == 0) { if (o->refcount == 1) {
switch(o->type) { switch(o->type) {
case REDIS_STRING: freeStringObject(o); break; case REDIS_STRING: freeStringObject(o); break;
case REDIS_LIST: freeListObject(o); break; case REDIS_LIST: freeListObject(o); break;
...@@ -189,8 +189,9 @@ void decrRefCount(void *obj) { ...@@ -189,8 +189,9 @@ void decrRefCount(void *obj) {
case REDIS_HASH: freeHashObject(o); break; case REDIS_HASH: freeHashObject(o); break;
default: redisPanic("Unknown object type"); break; default: redisPanic("Unknown object type"); break;
} }
o->ptr = NULL; /* defensive programming. We'll see NULL in traces. */
zfree(o); zfree(o);
} else {
o->refcount--;
} }
} }
......
...@@ -482,6 +482,7 @@ werr: ...@@ -482,6 +482,7 @@ werr:
int rdbSaveBackground(char *filename) { int rdbSaveBackground(char *filename) {
pid_t childpid; pid_t childpid;
long long start;
if (server.bgsavechildpid != -1 || if (server.bgsavechildpid != -1 ||
server.bgsavethread != (pthread_t) -1) return REDIS_ERR; server.bgsavethread != (pthread_t) -1) return REDIS_ERR;
...@@ -493,6 +494,7 @@ int rdbSaveBackground(char *filename) { ...@@ -493,6 +494,7 @@ int rdbSaveBackground(char *filename) {
return dsRdbSaveBackground(filename); return dsRdbSaveBackground(filename);
} }
start = ustime();
if ((childpid = fork()) == 0) { if ((childpid = fork()) == 0) {
int retval; int retval;
...@@ -503,6 +505,7 @@ int rdbSaveBackground(char *filename) { ...@@ -503,6 +505,7 @@ int rdbSaveBackground(char *filename) {
_exit((retval == REDIS_OK) ? 0 : 1); _exit((retval == REDIS_OK) ? 0 : 1);
} else { } else {
/* Parent */ /* Parent */
server.stat_fork_time = ustime()-start;
if (childpid == -1) { if (childpid == -1) {
redisLog(REDIS_WARNING,"Can't save in background: fork: %s", redisLog(REDIS_WARNING,"Can't save in background: fork: %s",
strerror(errno)); strerror(errno));
...@@ -1035,9 +1038,9 @@ void saveCommand(redisClient *c) { ...@@ -1035,9 +1038,9 @@ void saveCommand(redisClient *c) {
void bgsaveCommand(redisClient *c) { void bgsaveCommand(redisClient *c) {
if (server.bgsavechildpid != -1 || server.bgsavethread != (pthread_t)-1) { if (server.bgsavechildpid != -1 || server.bgsavethread != (pthread_t)-1) {
addReplyError(c,"Background save already in progress"); addReplyError(c,"Background save already in progress");
return; } else if (server.bgrewritechildpid != -1) {
} addReplyError(c,"Can't BGSAVE while AOF log rewriting is in progress");
if (rdbSaveBackground(server.dbfilename) == REDIS_OK) { } else if (rdbSaveBackground(server.dbfilename) == REDIS_OK) {
addReplyStatus(c,"Background saving started"); addReplyStatus(c,"Background saving started");
} else { } else {
addReply(c,shared.err); addReply(c,shared.err);
......
...@@ -48,7 +48,10 @@ ...@@ -48,7 +48,10 @@
#define REDIS_NOTUSED(V) ((void) V) #define REDIS_NOTUSED(V) ((void) V)
static struct config { static struct config {
int debug; aeEventLoop *el;
const char *hostip;
int hostport;
const char *hostsocket;
int numclients; int numclients;
int requests; int requests;
int liveclients; int liveclients;
...@@ -57,15 +60,11 @@ static struct config { ...@@ -57,15 +60,11 @@ static struct config {
int datasize; int datasize;
int randomkeys; int randomkeys;
int randomkeys_keyspacelen; int randomkeys_keyspacelen;
aeEventLoop *el;
char *hostip;
int hostport;
char *hostsocket;
int keepalive; int keepalive;
long long start; long long start;
long long totlatency; long long totlatency;
long long *latency; long long *latency;
char *title; const char *title;
list *clients; list *clients;
int quiet; int quiet;
int loop; int loop;
...@@ -227,7 +226,7 @@ static void writeHandler(aeEventLoop *el, int fd, void *privdata, int mask) { ...@@ -227,7 +226,7 @@ static void writeHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
} }
} }
static client createClient(char *cmd, int len) { static client createClient(const char *cmd, size_t len) {
client c = zmalloc(sizeof(struct _client)); client c = zmalloc(sizeof(struct _client));
if (config.hostsocket == NULL) { if (config.hostsocket == NULL) {
c->context = redisConnectNonBlock(config.hostip,config.hostport); c->context = redisConnectNonBlock(config.hostip,config.hostport);
...@@ -311,7 +310,7 @@ static void showLatencyReport(void) { ...@@ -311,7 +310,7 @@ static void showLatencyReport(void) {
} }
} }
static void benchmark(char *title, char *cmd, int len) { static void benchmark(const char *title, const char *cmd, int len) {
client c; client c;
config.title = title; config.title = title;
...@@ -328,73 +327,87 @@ static void benchmark(char *title, char *cmd, int len) { ...@@ -328,73 +327,87 @@ static void benchmark(char *title, char *cmd, int len) {
freeAllClients(); freeAllClients();
} }
void parseOptions(int argc, char **argv) { /* Returns number of consumed options. */
int parseOptions(int argc, const char **argv) {
int i; int i;
int lastarg;
int exit_status = 1;
for (i = 1; i < argc; i++) { for (i = 1; i < argc; i++) {
int lastarg = i==argc-1; lastarg = (i == (argc-1));
if (!strcmp(argv[i],"-c") && !lastarg) { if (!strcmp(argv[i],"-c")) {
config.numclients = atoi(argv[i+1]); if (lastarg) goto invalid;
i++; config.numclients = atoi(argv[++i]);
} else if (!strcmp(argv[i],"-n") && !lastarg) { } else if (!strcmp(argv[i],"-n")) {
config.requests = atoi(argv[i+1]); if (lastarg) goto invalid;
i++; config.requests = atoi(argv[++i]);
} else if (!strcmp(argv[i],"-k") && !lastarg) { } else if (!strcmp(argv[i],"-k")) {
config.keepalive = atoi(argv[i+1]); if (lastarg) goto invalid;
i++; config.keepalive = atoi(argv[++i]);
} else if (!strcmp(argv[i],"-h") && !lastarg) { } else if (!strcmp(argv[i],"-h")) {
config.hostip = argv[i+1]; if (lastarg) goto invalid;
i++; config.hostip = strdup(argv[++i]);
} else if (!strcmp(argv[i],"-p") && !lastarg) { } else if (!strcmp(argv[i],"-p")) {
config.hostport = atoi(argv[i+1]); if (lastarg) goto invalid;
i++; config.hostport = atoi(argv[++i]);
} else if (!strcmp(argv[i],"-s") && !lastarg) { } else if (!strcmp(argv[i],"-s")) {
config.hostsocket = argv[i+1]; if (lastarg) goto invalid;
i++; config.hostsocket = strdup(argv[++i]);
} else if (!strcmp(argv[i],"-d") && !lastarg) { } else if (!strcmp(argv[i],"-d")) {
config.datasize = atoi(argv[i+1]); if (lastarg) goto invalid;
i++; config.datasize = atoi(argv[++i]);
if (config.datasize < 1) config.datasize=1; if (config.datasize < 1) config.datasize=1;
if (config.datasize > 1024*1024) config.datasize = 1024*1024; if (config.datasize > 1024*1024) config.datasize = 1024*1024;
} else if (!strcmp(argv[i],"-r") && !lastarg) { } else if (!strcmp(argv[i],"-r")) {
if (lastarg) goto invalid;
config.randomkeys = 1; config.randomkeys = 1;
config.randomkeys_keyspacelen = atoi(argv[i+1]); config.randomkeys_keyspacelen = atoi(argv[++i]);
if (config.randomkeys_keyspacelen < 0) if (config.randomkeys_keyspacelen < 0)
config.randomkeys_keyspacelen = 0; config.randomkeys_keyspacelen = 0;
i++;
} else if (!strcmp(argv[i],"-q")) { } else if (!strcmp(argv[i],"-q")) {
config.quiet = 1; config.quiet = 1;
} else if (!strcmp(argv[i],"-l")) { } else if (!strcmp(argv[i],"-l")) {
config.loop = 1; config.loop = 1;
} else if (!strcmp(argv[i],"-D")) {
config.debug = 1;
} else if (!strcmp(argv[i],"-I")) { } else if (!strcmp(argv[i],"-I")) {
config.idlemode = 1; config.idlemode = 1;
} else if (!strcmp(argv[i],"--help")) {
exit_status = 0;
goto usage;
} else { } else {
printf("Wrong option '%s' or option argument missing\n\n",argv[i]); /* Assume the user meant to provide an option when the arg starts
printf("Usage: redis-benchmark [-h <host>] [-p <port>] [-c <clients>] [-n <requests]> [-k <boolean>]\n\n"); * with a dash. We're done otherwise and should use the remainder
printf(" -h <hostname> Server hostname (default 127.0.0.1)\n"); * as the command and arguments for running the benchmark. */
printf(" -p <port> Server port (default 6379)\n"); if (argv[i][0] == '-') goto invalid;
printf(" -s <socket> Server socket (overrides host and port)\n"); return i;
printf(" -c <clients> Number of parallel connections (default 50)\n");
printf(" -n <requests> Total number of requests (default 10000)\n");
printf(" -d <size> Data size of SET/GET value in bytes (default 2)\n");
printf(" -k <boolean> 1=keep alive 0=reconnect (default 1)\n");
printf(" -r <keyspacelen> Use random keys for SET/GET/INCR, random values for SADD\n");
printf(" Using this option the benchmark will get/set keys\n");
printf(" in the form mykey_rand000000012456 instead of constant\n");
printf(" keys, the <keyspacelen> argument determines the max\n");
printf(" number of values for the random number. For instance\n");
printf(" if set to 10 only rand000000000000 - rand000000000009\n");
printf(" range will be allowed.\n");
printf(" -q Quiet. Just show query/sec values\n");
printf(" -l Loop. Run the tests forever\n");
printf(" -I Idle mode. Just open N idle connections and wait.\n");
printf(" -D Debug mode. more verbose.\n");
exit(1);
} }
} }
return i;
invalid:
printf("Invalid option \"%s\" or option argument missing\n\n",argv[i]);
usage:
printf("Usage: redis-benchmark [-h <host>] [-p <port>] [-c <clients>] [-n <requests]> [-k <boolean>]\n\n");
printf(" -h <hostname> Server hostname (default 127.0.0.1)\n");
printf(" -p <port> Server port (default 6379)\n");
printf(" -s <socket> Server socket (overrides host and port)\n");
printf(" -c <clients> Number of parallel connections (default 50)\n");
printf(" -n <requests> Total number of requests (default 10000)\n");
printf(" -d <size> Data size of SET/GET value in bytes (default 2)\n");
printf(" -k <boolean> 1=keep alive 0=reconnect (default 1)\n");
printf(" -r <keyspacelen> Use random keys for SET/GET/INCR, random values for SADD\n");
printf(" Using this option the benchmark will get/set keys\n");
printf(" in the form mykey_rand000000012456 instead of constant\n");
printf(" keys, the <keyspacelen> argument determines the max\n");
printf(" number of values for the random number. For instance\n");
printf(" if set to 10 only rand000000000000 - rand000000000009\n");
printf(" range will be allowed.\n");
printf(" -q Quiet. Just show query/sec values\n");
printf(" -l Loop. Run the tests forever\n");
printf(" -I Idle mode. Just open N idle connections and wait.\n");
exit(exit_status);
} }
int showThroughput(struct aeEventLoop *eventLoop, long long id, void *clientData) { int showThroughput(struct aeEventLoop *eventLoop, long long id, void *clientData) {
...@@ -409,14 +422,16 @@ int showThroughput(struct aeEventLoop *eventLoop, long long id, void *clientData ...@@ -409,14 +422,16 @@ int showThroughput(struct aeEventLoop *eventLoop, long long id, void *clientData
return 250; /* every 250ms */ return 250; /* every 250ms */
} }
int main(int argc, char **argv) { int main(int argc, const char **argv) {
int i; int i;
char *data, *cmd;
int len;
client c; client c;
signal(SIGHUP, SIG_IGN); signal(SIGHUP, SIG_IGN);
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
config.debug = 0;
config.numclients = 50; config.numclients = 50;
config.requests = 10000; config.requests = 10000;
config.liveclients = 0; config.liveclients = 0;
...@@ -436,7 +451,10 @@ int main(int argc, char **argv) { ...@@ -436,7 +451,10 @@ int main(int argc, char **argv) {
config.hostport = 6379; config.hostport = 6379;
config.hostsocket = NULL; config.hostsocket = NULL;
parseOptions(argc,argv); i = parseOptions(argc,argv);
argc -= i;
argv += i;
config.latency = zmalloc(sizeof(long long)*config.requests); config.latency = zmalloc(sizeof(long long)*config.requests);
if (config.keepalive == 0) { if (config.keepalive == 0) {
...@@ -451,10 +469,25 @@ int main(int argc, char **argv) { ...@@ -451,10 +469,25 @@ int main(int argc, char **argv) {
/* and will wait for every */ /* and will wait for every */
} }
do { /* Run benchmark with command in the remainder of the arguments. */
char *data, *cmd; if (argc) {
int len; sds title = sdsnew(argv[0]);
for (i = 1; i < argc; i++) {
title = sdscatlen(title, " ", 1);
title = sdscatlen(title, (char*)argv[i], strlen(argv[i]));
}
do {
len = redisFormatCommandArgv(&cmd,argc,argv,NULL);
benchmark(title,cmd,len);
free(cmd);
} while(config.loop);
return 0;
}
/* Run default benchmark suite. */
do {
data = zmalloc(config.datasize+1); data = zmalloc(config.datasize+1);
memset(data,'x',config.datasize); memset(data,'x',config.datasize);
data[config.datasize] = '\0'; data[config.datasize] = '\0';
......
...@@ -55,6 +55,7 @@ static struct config { ...@@ -55,6 +55,7 @@ static struct config {
int hostport; int hostport;
char *hostsocket; char *hostsocket;
long repeat; long repeat;
long interval;
int dbnum; int dbnum;
int interactive; int interactive;
int shutdown; int shutdown;
...@@ -87,9 +88,11 @@ static long long mstime(void) { ...@@ -87,9 +88,11 @@ static long long mstime(void) {
static void cliRefreshPrompt(void) { static void cliRefreshPrompt(void) {
if (config.dbnum == 0) if (config.dbnum == 0)
snprintf(config.prompt,sizeof(config.prompt),"redis> "); snprintf(config.prompt,sizeof(config.prompt),"redis %s:%d> ",
config.hostip, config.hostport);
else else
snprintf(config.prompt,sizeof(config.prompt),"redis:%d> ",config.dbnum); snprintf(config.prompt,sizeof(config.prompt),"redis %s:%d[%d]> ",
config.hostip, config.hostport, config.dbnum);
} }
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
...@@ -314,10 +317,9 @@ static int cliConnect(int force) { ...@@ -314,10 +317,9 @@ static int cliConnect(int force) {
return REDIS_OK; return REDIS_OK;
} }
static void cliPrintContextErrorAndExit() { static void cliPrintContextError() {
if (context == NULL) return; if (context == NULL) return;
fprintf(stderr,"Error: %s\n",context->errstr); fprintf(stderr,"Error: %s\n",context->errstr);
exit(1);
} }
static sds cliFormatReplyTTY(redisReply *r, char *prefix) { static sds cliFormatReplyTTY(redisReply *r, char *prefix) {
...@@ -436,7 +438,8 @@ static int cliReadReply(int output_raw_strings) { ...@@ -436,7 +438,8 @@ static int cliReadReply(int output_raw_strings) {
if (context->err == REDIS_ERR_EOF) if (context->err == REDIS_ERR_EOF)
return REDIS_ERR; return REDIS_ERR;
} }
cliPrintContextErrorAndExit(); cliPrintContextError();
exit(1);
return REDIS_ERR; /* avoid compiler warning */ return REDIS_ERR; /* avoid compiler warning */
} }
...@@ -462,10 +465,7 @@ static int cliSendCommand(int argc, char **argv, int repeat) { ...@@ -462,10 +465,7 @@ static int cliSendCommand(int argc, char **argv, int repeat) {
size_t *argvlen; size_t *argvlen;
int j, output_raw; int j, output_raw;
if (context == NULL) { if (context == NULL) return REDIS_ERR;
printf("Not connected, please use: connect <host> <port>\n");
return REDIS_OK;
}
output_raw = 0; output_raw = 0;
if (!strcasecmp(command,"info") || if (!strcasecmp(command,"info") ||
...@@ -518,6 +518,8 @@ static int cliSendCommand(int argc, char **argv, int repeat) { ...@@ -518,6 +518,8 @@ static int cliSendCommand(int argc, char **argv, int repeat) {
cliRefreshPrompt(); cliRefreshPrompt();
} }
} }
if (config.interval) usleep(config.interval);
fflush(stdout); /* Make it grep friendly */
} }
free(argvlen); free(argvlen);
...@@ -553,6 +555,10 @@ static int parseOptions(int argc, char **argv) { ...@@ -553,6 +555,10 @@ static int parseOptions(int argc, char **argv) {
} else if (!strcmp(argv[i],"-r") && !lastarg) { } else if (!strcmp(argv[i],"-r") && !lastarg) {
config.repeat = strtoll(argv[i+1],NULL,10); config.repeat = strtoll(argv[i+1],NULL,10);
i++; i++;
} else if (!strcmp(argv[i],"-i") && !lastarg) {
double seconds = atof(argv[i+1]);
config.interval = seconds*1000000;
i++;
} else if (!strcmp(argv[i],"-n") && !lastarg) { } else if (!strcmp(argv[i],"-n") && !lastarg) {
config.dbnum = atoi(argv[i+1]); config.dbnum = atoi(argv[i+1]);
i++; i++;
...@@ -605,6 +611,8 @@ static void usage() { ...@@ -605,6 +611,8 @@ static void usage() {
" -s <socket> Server socket (overrides hostname and port)\n" " -s <socket> Server socket (overrides hostname and port)\n"
" -a <password> Password to use when connecting to the server\n" " -a <password> Password to use when connecting to the server\n"
" -r <repeat> Execute specified command N times\n" " -r <repeat> Execute specified command N times\n"
" -i <interval> When -r is used, waits <interval> seconds per command.\n"
" It is possible to specify sub-second times like -i 0.1.\n"
" -n <db> Database number\n" " -n <db> Database number\n"
" -x Read last argument from STDIN\n" " -x Read last argument from STDIN\n"
" -d <delimiter> Multi-bulk delimiter in for raw formatting (default: \\n)\n" " -d <delimiter> Multi-bulk delimiter in for raw formatting (default: \\n)\n"
...@@ -616,6 +624,7 @@ static void usage() { ...@@ -616,6 +624,7 @@ static void usage() {
" cat /etc/passwd | redis-cli -x set mypasswd\n" " cat /etc/passwd | redis-cli -x set mypasswd\n"
" redis-cli get mypasswd\n" " redis-cli get mypasswd\n"
" redis-cli -r 100 lpush mylist x\n" " redis-cli -r 100 lpush mylist x\n"
" redis-cli -r 100 -i 1 info | grep used_memory_human:\n"
"\n" "\n"
"When no command is given, redis-cli starts in interactive mode.\n" "When no command is given, redis-cli starts in interactive mode.\n"
"Type \"help\" in interactive mode for information on available commands.\n" "Type \"help\" in interactive mode for information on available commands.\n"
...@@ -681,14 +690,25 @@ static void repl() { ...@@ -681,14 +690,25 @@ static void repl() {
linenoiseClearScreen(); linenoiseClearScreen();
} else { } else {
long long start_time = mstime(), elapsed; long long start_time = mstime(), elapsed;
int repeat, skipargs = 0;
repeat = atoi(argv[0]);
if (repeat) {
skipargs = 1;
} else {
repeat = 1;
}
if (cliSendCommand(argc,argv,1) != REDIS_OK) { if (cliSendCommand(argc-skipargs,argv+skipargs,repeat)
!= REDIS_OK)
{
cliConnect(1); cliConnect(1);
/* If we still cannot send the command, /* If we still cannot send the command print error.
* print error and abort. */ * We'll try to reconnect the next time. */
if (cliSendCommand(argc,argv,1) != REDIS_OK) if (cliSendCommand(argc-skipargs,argv+skipargs,repeat)
cliPrintContextErrorAndExit(); != REDIS_OK)
cliPrintContextError();
} }
elapsed = mstime()-start_time; elapsed = mstime()-start_time;
if (elapsed >= 500) { if (elapsed >= 500) {
...@@ -726,6 +746,7 @@ int main(int argc, char **argv) { ...@@ -726,6 +746,7 @@ int main(int argc, char **argv) {
config.hostport = 6379; config.hostport = 6379;
config.hostsocket = NULL; config.hostsocket = NULL;
config.repeat = 1; config.repeat = 1;
config.interval = 0;
config.dbnum = 0; config.dbnum = 0;
config.interactive = 0; config.interactive = 0;
config.shutdown = 0; config.shutdown = 0;
...@@ -741,11 +762,15 @@ int main(int argc, char **argv) { ...@@ -741,11 +762,15 @@ int main(int argc, char **argv) {
argc -= firstarg; argc -= firstarg;
argv += firstarg; argv += firstarg;
/* Try to connect */
if (cliConnect(0) != REDIS_OK) exit(1);
/* Start interactive mode when no command is provided */ /* Start interactive mode when no command is provided */
if (argc == 0) repl(); if (argc == 0) {
/* Note that in repl mode we don't abort on connection error.
* A new attempt will be performed for every command send. */
cliConnect(0);
repl();
}
/* Otherwise, we have some arguments to execute */ /* Otherwise, we have some arguments to execute */
if (cliConnect(0) != REDIS_OK) exit(1);
return noninteractive(argc,convertToSds(argc,argv)); return noninteractive(argc,convertToSds(argc,argv));
} }
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