CINXE.COM

SETNX – Redis

<!DOCTYPE html> <html> <head><script type="text/javascript" src="/_static/js/bundle-playback.js?v=HxkREWBo" charset="utf-8"></script> <script type="text/javascript" src="/_static/js/wombat.js?v=txqj7nKC" charset="utf-8"></script> <script>window.RufflePlayer=window.RufflePlayer||{};window.RufflePlayer.config={"autoplay":"on","unmuteOverlay":"hidden"};</script> <script type="text/javascript" src="/_static/js/ruffle/ruffle.js"></script> <script type="text/javascript"> __wm.init("https://web.archive.org/web"); __wm.wombat("http://redis.io/commands/setnx","20130509025805","https://web.archive.org/","web","/_static/", "1368068285"); </script> <link rel="stylesheet" type="text/css" href="/_static/css/banner-styles.css?v=S1zqJCYt" /> <link rel="stylesheet" type="text/css" href="/_static/css/iconochive.css?v=3PDvdIFv" /> <!-- End Wayback Rewrite JS Include --> <meta charset="utf-8"/> <link href="/web/20130509025805cs_/http://redis.io/styles.css?1333128600" rel="stylesheet" type="text/css"/> <link href="/web/20130509025805im_/http://redis.io/images/favicon.png" rel="shortcut icon"/> <link href="/web/20130509025805/http://redis.io/opensearch.xml" rel="search" title="Look up a Redis command" type="application/opensearchdescription+xml"/> <script src="https://web.archive.org/web/20130509025805js_/http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script> <script async="async" defer="defer" src="/web/20130509025805js_/http://redis.io/app.js?1362159350"></script> <meta content="width=device-width, minimum-scale=1.0, maximum-scale=1.0" name="viewport"/> <title> SETNX – Redis </title> <script type="text/javascript"> //<![CDATA[ var _gaq = _gaq || []; _gaq.push(['_setAccount', 'UA-20243082-1']); _gaq.push(['_trackPageview']); (function() { var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; ga.src = ('https:' == document.location.protocol ? 'https://web.archive.org/web/20130509025805/https://ssl' : 'https://web.archive.org/web/20130509025805/http://www') + '.google-analytics.com/ga.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); })(); //]]> </script> </head> <body class=""> <header> <div class="container"> <a href="/web/20130509025805/http://redis.io/"> <img alt="Redis" height="30" src="/web/20130509025805im_/http://redis.io/images/redis.png" width="93"/> </a> <nav> <a href="/web/20130509025805/http://redis.io/commands">Commands</a> <a href="/web/20130509025805/http://redis.io/clients">Clients</a> <a href="/web/20130509025805/http://redis.io/documentation">Documentation</a> <a href="/web/20130509025805/http://redis.io/community">Community</a> <a href="/web/20130509025805/http://redis.io/download">Download</a> <a href="https://web.archive.org/web/20130509025805/https://github.com/antirez/redis/issues">Issues</a> <a href="/web/20130509025805/http://redis.io/topics/license">License</a> </nav> </div> </header> <div class="text"> <h1 class="command"> <span class="name">SETNX</span> <span class="arg">key</span> <span class="arg">value</span> </h1> <article> <aside> <h2> Related commands </h2> <ul> <li> <a href="/web/20130509025805/http://redis.io/commands/append"> APPEND </a> </li> <li> <a href="/web/20130509025805/http://redis.io/commands/bitcount"> BITCOUNT </a> </li> <li> <a href="/web/20130509025805/http://redis.io/commands/bitop"> BITOP </a> </li> <li> <a href="/web/20130509025805/http://redis.io/commands/decr"> DECR </a> </li> <li> <a href="/web/20130509025805/http://redis.io/commands/decrby"> DECRBY </a> </li> <li> <a href="/web/20130509025805/http://redis.io/commands/get"> GET </a> </li> <li> <a href="/web/20130509025805/http://redis.io/commands/getbit"> GETBIT </a> </li> <li> <a href="/web/20130509025805/http://redis.io/commands/getrange"> GETRANGE </a> </li> <li> <a href="/web/20130509025805/http://redis.io/commands/getset"> GETSET </a> </li> <li> <a href="/web/20130509025805/http://redis.io/commands/incr"> INCR </a> </li> <li> <a href="/web/20130509025805/http://redis.io/commands/incrby"> INCRBY </a> </li> <li> <a href="/web/20130509025805/http://redis.io/commands/incrbyfloat"> INCRBYFLOAT </a> </li> <li> <a href="/web/20130509025805/http://redis.io/commands/mget"> MGET </a> </li> <li> <a href="/web/20130509025805/http://redis.io/commands/mset"> MSET </a> </li> <li> <a href="/web/20130509025805/http://redis.io/commands/msetnx"> MSETNX </a> </li> <li> <a href="/web/20130509025805/http://redis.io/commands/psetex"> PSETEX </a> </li> <li> <a href="/web/20130509025805/http://redis.io/commands/set"> SET </a> </li> <li> <a href="/web/20130509025805/http://redis.io/commands/setbit"> SETBIT </a> </li> <li> <a href="/web/20130509025805/http://redis.io/commands/setex"> SETEX </a> </li> <li> <a href="/web/20130509025805/http://redis.io/commands/setnx"> <strong>SETNX</strong> </a> </li> <li> <a href="/web/20130509025805/http://redis.io/commands/setrange"> SETRANGE </a> </li> <li> <a href="/web/20130509025805/http://redis.io/commands/strlen"> STRLEN </a> </li> </ul> </aside> <div class="metadata"> <p><strong>Available since 1.0.0.</strong></p> <p><strong>Time complexity:</strong> O(1)</p> </div> <p>Set <code>key</code> to hold string <code>value</code> if <code>key</code> does not exist. In that case, it is equal to <a href="/web/20130509025805/http://redis.io/commands/set">SET</a>. When <code>key</code> already holds a value, no operation is performed. <a href="/web/20130509025805/http://redis.io/commands/setnx">SETNX</a> is short for &quot;<strong>SET</strong> if <strong>N</strong> ot e <strong>X</strong> ists&quot;.</p> <h2>Return value</h2> <p><a href="/web/20130509025805/http://redis.io/topics/protocol#integer-reply">Integer reply</a>, specifically:</p> <ul> <li><code>1</code> if the key was set</li> <li><code>0</code> if the key was not set</li> </ul> <h2>Examples</h2> <div class="example" data-session="a2dd882f7e087a375e5f9d04229e84eb"> <span class="monospace prompt">redis&gt;&nbsp;</span> <span class="monospace command">SETNX mykey &quot;Hello&quot;</span> <pre>(integer) 1</pre> <span class="monospace prompt">redis&gt;&nbsp;</span> <span class="monospace command">SETNX mykey &quot;World&quot;</span> <pre>(integer) 0</pre> <span class="monospace prompt">redis&gt;&nbsp;</span> <span class="monospace command">GET mykey</span> <pre>"Hello"</pre><form> <span class="monospace prompt">redis&gt;&nbsp;</span> <input autocomplete="off" name="command" spellcheck="false" type="text"/> </form></div> <h2>Design pattern: Locking with <code>SETNX</code></h2> <p><strong>NOTE:</strong> Starting with Redis 2.6.12 it is possible to create a much simpler locking primitive using the <a href="/web/20130509025805/http://redis.io/commands/set">SET</a> command to acquire the lock, and a simple Lua script to release the lock. The pattern is documented in the <a href="/web/20130509025805/http://redis.io/commands/set">SET</a> command page.</p> <p>The old <a href="/web/20130509025805/http://redis.io/commands/setnx">SETNX</a> based pattern is documented below for historical reasons.</p> <p><a href="/web/20130509025805/http://redis.io/commands/setnx">SETNX</a> can be used as a locking primitive. For example, to acquire the lock of the key <code>foo</code>, the client could try the following:</p> <pre><code>SETNX lock.foo &lt;current Unix time + lock timeout + 1&gt;&#x000A;</code></pre> <p>If <a href="/web/20130509025805/http://redis.io/commands/setnx">SETNX</a> returns <code>1</code> the client acquired the lock, setting the <code>lock.foo</code> key to the Unix time at which the lock should no longer be considered valid. The client will later use <code>DEL lock.foo</code> in order to release the lock.</p> <p>If <a href="/web/20130509025805/http://redis.io/commands/setnx">SETNX</a> returns <code>0</code> the key is already locked by some other client. We can either return to the caller if it&#39;s a non blocking lock, or enter a loop retrying to hold the lock until we succeed or some kind of timeout expires.</p> <h3>Handling deadlocks</h3> <p>In the above locking algorithm there is a problem: what happens if a client fails, crashes, or is otherwise not able to release the lock? It&#39;s possible to detect this condition because the lock key contains a UNIX timestamp. If such a timestamp is equal to the current Unix time the lock is no longer valid.</p> <p>When this happens we can&#39;t just call <a href="/web/20130509025805/http://redis.io/commands/del">DEL</a> against the key to remove the lock and then try to issue a <a href="/web/20130509025805/http://redis.io/commands/setnx">SETNX</a>, as there is a race condition here, when multiple clients detected an expired lock and are trying to release it.</p> <ul> <li>C1 and C2 read <code>lock.foo</code> to check the timestamp, because they both received <code>0</code> after executing <a href="/web/20130509025805/http://redis.io/commands/setnx">SETNX</a>, as the lock is still held by C3 that crashed after holding the lock.</li> <li>C1 sends <code>DEL lock.foo</code></li> <li>C1 sends <code>SETNX lock.foo</code> and it succeeds</li> <li>C2 sends <code>DEL lock.foo</code></li> <li>C2 sends <code>SETNX lock.foo</code> and it succeeds</li> <li><strong>ERROR</strong>: both C1 and C2 acquired the lock because of the race condition.</li> </ul> <p>Fortunately, it&#39;s possible to avoid this issue using the following algorithm. Let&#39;s see how C4, our sane client, uses the good algorithm:</p> <ul> <li><p>C4 sends <code>SETNX lock.foo</code> in order to acquire the lock</p></li> <li><p>The crashed client C3 still holds it, so Redis will reply with <code>0</code> to C4.</p></li> <li><p>C4 sends <code>GET lock.foo</code> to check if the lock expired. If it is not, it will sleep for some time and retry from the start.</p></li> <li><p>Instead, if the lock is expired because the Unix time at <code>lock.foo</code> is older than the current Unix time, C4 tries to perform:</p> <pre><code>GETSET lock.foo &lt;current Unix timestamp + lock timeout + 1&gt;&#x000A;</code></pre></li> <li><p>Because of the <a href="/web/20130509025805/http://redis.io/commands/getset">GETSET</a> semantic, C4 can check if the old value stored at <code>key</code> is still an expired timestamp. If it is, the lock was acquired.</p></li> <li><p>If another client, for instance C5, was faster than C4 and acquired the lock with the <a href="/web/20130509025805/http://redis.io/commands/getset">GETSET</a> operation, the C4 <a href="/web/20130509025805/http://redis.io/commands/getset">GETSET</a> operation will return a non expired timestamp. C4 will simply restart from the first step. Note that even if C4 set the key a bit a few seconds in the future this is not a problem.</p></li> </ul> <p><strong>Important note</strong>: In order to make this locking algorithm more robust, a client holding a lock should always check the timeout didn&#39;t expire before unlocking the key with <a href="/web/20130509025805/http://redis.io/commands/del">DEL</a> because client failures can be complex, not just crashing but also blocking a lot of time against some operations and trying to issue <a href="/web/20130509025805/http://redis.io/commands/del">DEL</a> after a lot of time (when the LOCK is already held by another client).</p> </article> </div> <div class="text" id="comments"> <div id="disqus_thread"></div> <script type="text/javascript"> //<![CDATA[ var disqus_shortname = 'redisio'; // The following are highly recommended additional parameters. Remove the slashes in front to use. var disqus_identifier = 'command_setnx'; var disqus_url = 'https://web.archive.org/web/20130509025805/http://redis.io/commands/setnx'; /* * * DON'T EDIT BELOW THIS LINE * * */ (function() { var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js'; (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); })(); //]]> </script> <a class="dsq-brlink" href="https://web.archive.org/web/20130509025805/http://disqus.com/"> Comments powered by <span class="logo-disqus"> Disqus </span> </a> </div> <footer> <p> This website is <a href="https://web.archive.org/web/20130509025805/https://github.com/antirez/redis-io">open source software</a> developed by <a href="https://web.archive.org/web/20130509025805/http://citrusbyte.com/">Citrusbyte</a>. <br> The Redis logo was designed by <a href="https://web.archive.org/web/20130509025805/http://www.carlosprioglio.com/">Carlos Prioglio</a>. See more <a href="https://web.archive.org/web/20130509025805/http://redis.io/topics/sponsors">credits</a>. </p> <div class="sponsor"> Sponsored by <img alt="VMWare" height="19" src="/web/20130509025805im_/http://redis.io/images/vmware.png" width="121"/> </div> </footer> </body> </html> <!-- FILE ARCHIVED ON 02:58:05 May 09, 2013 AND RETRIEVED FROM THE INTERNET ARCHIVE ON 11:22:47 Dec 11, 2024. JAVASCRIPT APPENDED BY WAYBACK MACHINE, COPYRIGHT INTERNET ARCHIVE. ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C. SECTION 108(a)(3)). --> <!-- playback timings (ms): captures_list: 0.536 exclusion.robots: 0.027 exclusion.robots.policy: 0.016 esindex: 0.011 cdx.remote: 7.103 LoadShardBlock: 258.124 (3) PetaboxLoader3.datanode: 201.745 (4) load_resource: 252.046 PetaboxLoader3.resolve: 130.891 -->

Pages: 1 2 3 4 5 6 7 8 9 10