Browse files

Merge branch 'master' of github.com:/antirez/redis-doc

  • Loading branch information...
2 parents 8ef2561 + c500f96 commit 9ecb4ec6477e472212d406b1108b34657d63913c @antirez committed Jul 8, 2012
Showing with 2,953 additions and 2,051 deletions.
  1. +92 −53 README.md
  2. +41 −0 Rakefile
  3. +28 −2 commands.json
  4. +40 −27 commands/append.md
  5. +7 −8 commands/auth.md
  6. +22 −6 commands/bgrewriteaof.md
  7. +8 −6 commands/bgsave.md
  8. +42 −35 commands/bitcount.md
  9. +35 −30 commands/bitop.md
  10. +63 −53 commands/blpop.md
  11. +22 −18 commands/brpop.md
  12. +8 −9 commands/brpoplpush.md
  13. +41 −29 commands/config get.md
  14. +40 −28 commands/config set.md
  15. +1 −3 commands/dbsize.md
  16. +11 −11 commands/decr.md
  17. +8 −8 commands/decrby.md
  18. +7 −6 commands/del.md
  19. +4 −3 commands/discard.md
  20. +22 −10 commands/dump.md
  21. +3 −3 commands/echo.md
  22. +393 −337 commands/eval.md
  23. +3 −0 commands/evalsha.md
  24. +11 −10 commands/exec.md
  25. +5 −5 commands/exists.md
  26. +88 −75 commands/expire.md
  27. +15 −12 commands/expireat.md
  28. +3 −1 commands/flushall.md
  29. +2 −1 commands/flushdb.md
  30. +7 −6 commands/get.md
  31. +10 −9 commands/getbit.md
  32. +13 −11 commands/getrange.md
  33. +16 −14 commands/getset.md
  34. +13 −11 commands/hdel.md
  35. +5 −5 commands/hexists.md
  36. +5 −5 commands/hget.md
  37. +7 −7 commands/hgetall.md
  38. +10 −10 commands/hincrby.md
  39. +17 −9 commands/hincrbyfloat.md
  40. +5 −5 commands/hkeys.md
  41. +5 −5 commands/hlen.md
  42. +7 −7 commands/hmget.md
  43. +8 −7 commands/hmset.md
  44. +7 −7 commands/hset.md
  45. +8 −7 commands/hsetnx.md
  46. +5 −5 commands/hvals.md
  47. +113 −91 commands/incr.md
  48. +8 −8 commands/incrby.md
  49. +21 −11 commands/incrbyfloat.md
  50. +43 −36 commands/info.md
  51. +21 −16 commands/keys.md
  52. +3 −3 commands/lastsave.md
  53. +12 −11 commands/lindex.md
  54. +8 −8 commands/linsert.md
  55. +5 −5 commands/llen.md
  56. +7 −7 commands/lpop.md
  57. +16 −9 commands/lpush.md
  58. +11 −10 commands/lpushx.md
  59. +24 −22 commands/lrange.md
  60. +13 −13 commands/lrem.md
  61. +10 −10 commands/lset.md
  62. +24 −18 commands/ltrim.md
  63. +8 −7 commands/mget.md
  64. +31 −12 commands/migrate.md
  65. +71 −29 commands/monitor.md
  66. +4 −4 commands/move.md
  67. +11 −10 commands/mset.md
  68. +13 −11 commands/msetnx.md
  69. +4 −3 commands/multi.md
  70. +58 −34 commands/object.md
  71. +10 −8 commands/persist.md
  72. +6 −5 commands/pexpire.md
  73. +8 −7 commands/pexpireat.md
  74. +6 −5 commands/ping.md
  75. +7 −5 commands/psetex.md
  76. +10 −8 commands/pttl.md
  77. +6 −5 commands/punsubscribe.md
  78. +3 −3 commands/quit.md
  79. +0 −1 commands/randomkey.md
  80. +9 −8 commands/rename.md
  81. +6 −6 commands/renamenx.md
  82. +20 −15 commands/restore.md
  83. +7 −7 commands/rpop.md
  84. +47 −40 commands/rpoplpush.md
  85. +16 −9 commands/rpush.md
  86. +11 −10 commands/rpushx.md
  87. +14 −11 commands/sadd.md
  88. +12 −3 commands/save.md
  89. +7 −7 commands/scard.md
  90. +17 −8 commands/script exists.md
  91. +2 −1 commands/script flush.md
  92. +13 −5 commands/script kill.md
  93. +11 −6 commands/script load.md
  94. +15 −13 commands/sdiff.md
  95. +2 −2 commands/sdiffstore.md
  96. +0 −1 commands/select.md
  97. +6 −6 commands/set.md
  98. +18 −16 commands/setbit.md
  99. +14 −12 commands/setex.md
  100. +50 −38 commands/setnx.md
  101. +27 −25 commands/setrange.md
  102. +20 −13 commands/shutdown.md
  103. +18 −16 commands/sinter.md
  104. +5 −5 commands/sismember.md
  105. +12 −11 commands/slaveof.md
  106. +49 −41 commands/slowlog.md
  107. +5 −5 commands/smembers.md
  108. +17 −15 commands/smove.md
  109. +82 −51 commands/sort.md
  110. +9 −9 commands/spop.md
  111. +6 −6 commands/srandmember.md
  112. +16 −13 commands/srem.md
  113. +7 −6 commands/strlen.md
  114. +3 −3 commands/subscribe.md
  115. +16 −15 commands/sunion.md
  116. +8 −6 commands/time.md
  117. +9 −8 commands/ttl.md
  118. +8 −8 commands/type.md
  119. +6 −5 commands/unsubscribe.md
  120. +3 −1 commands/unwatch.md
  121. +4 −1 commands/watch.md
  122. +22 −12 commands/zadd.md
  123. +7 −7 commands/zcard.md
  124. +11 −11 commands/zcount.md
  125. +13 −12 commands/zincrby.md
  126. +16 −15 commands/zinterstore.md
  127. +25 −22 commands/zrange.md
  128. +28 −23 commands/zrangebyscore.md
  129. +11 −10 commands/zrank.md
  130. +14 −10 commands/zrem.md
  131. +15 −13 commands/zremrangebyrank.md
  132. +7 −7 commands/zremrangebyscore.md
  133. +10 −10 commands/zrevrange.md
  134. +16 −15 commands/zrevrangebyscore.md
  135. +11 −10 commands/zrevrank.md
  136. +6 −6 commands/zscore.md
  137. +21 −20 commands/zunionstore.md
  138. +253 −0 remarkdown.rb
  139. +2 −2 topics/data-types-intro.md
  140. +2 −2 topics/latency.md
  141. +1 −1 topics/mass-insert.md
  142. +2 −2 topics/persistence.md
  143. +25 −0 wordlist
View
145 README.md
@@ -1,84 +1,123 @@
-Redis documentation
-===
+# Redis documentation
+## Clients
-Clients
----
+All clients are listed in the `clients.json` file.
+Each key in the JSON object represents a single client library.
+For example:
-All clients are listed in the `clients.json` file. Each key in the JSON
-object represents a single client library. For example:
+```
+"Rediska": {
- "Rediska": {
+ # A programming language should be specified.
+ "language": "PHP",
- # A programming language should be specified.
- "language": "PHP",
+ # If the project has a website of its own, put it here.
+ # Otherwise, lose the "url" key.
+ "url": "http://rediska.geometria-lab.net",
- # If the project has a website of its own, put it here.
- # Otherwise, lose the "url" key.
- "url": "http://rediska.geometria-lab.net",
+ # A URL pointing to the repository where users can
+ # find the code.
+ "repository": "http://github.com/Shumkov/Rediska",
- # A URL pointing to the repository where users can
- # find the code.
- "repository": "http://github.com/Shumkov/Rediska",
+ # A short, free-text description of the client.
+ # Should be objective. The goal is to help users
+ # choose the correct client they need.
+ "description": "A PHP client",
- # A short, free-text description of the client.
- # Should be objective. The goal is to help users
- # choose the correct client they need.
- "description": "A PHP client",
+ # An array of Twitter usernames for the authors
+ # and maintainers of the library.
+ "authors": ["shumkov"]
- # An array of Twitter usernames for the authors
- # and maintainers of the library.
- "authors": ["shumkov"]
+}
+```
- }
-
-
-Commands
----
+## Commands
Redis commands are described in the `commands.json` file.
For each command there's a Markdown file with a complete, human-readable
-description. We process this Markdown to provide a better experience, so
-some things to take into account:
+description.
+We process this Markdown to provide a better experience, so some things to take
+into account:
+
+* Inside text, all commands should be written in all caps, in between
+ backticks.
+ For example: `INCR`.
+
+* You can use some magic keywords to name common elements in Redis.
+ For example: `@multi-bulk-reply`.
+ These keywords will get expanded and auto-linked to relevant parts of the
+ documentation.
+
+There should be at least two predefined sections: description and return value.
+The return value section is marked using the @return keyword:
+
+```
+Returns all keys matching the given pattern.
+
+@return
+
+@multi-bulk-reply: all the keys that matched the pattern.
+```
+
+## Styling guidelines
+
+Please use the following formatting rules:
+
+* Wrap lines to 80 characters.
+* Start every sentence on a new line.
+
+Luckily, this repository comes with an automated Markdown formatter.
+To only reformat the files you have modified, first stage them using `git add`
+(this makes sure that your changes won't be lost in case of an error), then run
+the formatter:
-* Inside text, all commands should be written in all caps, in between
-backticks. For example: <code>`INCR`</code>.
+```
+$ rake format:cached
+```
-* You can use some magic keywords to name common elements in Redis. For
-example: `@multi-bulk-reply`. These keywords will get expanded and
-auto-linked to relevant parts of the documentation.
+The formatter has the following dependencies:
-There should be at least two predefined sections: description and
-return value. The return value section is marked using the @return
-keyword:
+* Redcarpet
+* Nokogiri
+* The `par` tool
- Returns all keys matching the given pattern.
+Installation of the Ruby gems:
- @return
+```
+gem install redcarpet nokogiri
+```
- @multi-bulk-reply: all the keys that matched the pattern.
+Installation of par (OSX):
+```
+brew install par
+```
-Styling guidelines
----
+Installation of par (Ubuntu):
-Please wrap your text to 80 characters. You can easily accomplish this
-using a CLI tool called `par`.
+```
+sudo apt-get install par
+```
+## Checking your work
-Checking your work
----
+Once you're done, the very least you should do is make sure that all files
+compile properly.
+You can do this by running Rake inside your working directory.
-Once you're done, the very least you should do is make sure that all
-files compile properly. You can do this by running Rake inside your
-working directory.
+```
+$ rake parse
+```
- $ rake parse
+Additionally, if you have [Aspell][han] installed, you can spell check the
+documentation:
-Additionally, if you have [Aspell](http://aspell.net/) installed, you
-can spell check the documentation:
+[han]: http://aspell.net/
- $ rake spellcheck
+```
+$ rake spellcheck
+```
Exceptions can be added to `./wordlist`.
View
41 Rakefile
@@ -39,3 +39,44 @@ task :spellcheck do
puts "#{file}: #{words.uniq.sort.join(" ")}" if words.any?
end
end
+
+namespace :format do
+
+ require "./remarkdown"
+
+ def format(file)
+ return unless File.exist?(file)
+
+ STDOUT.print "formatting #{file}..."
+ STDOUT.flush
+
+ body = File.read(file)
+ body = ReMarkdown.new(body).to_s
+ body = body.gsub(/^\s+$/, "")
+
+ File.open(file, "w") do |f|
+ f.print body
+ end
+
+ STDOUT.puts
+ end
+
+ desc "Reformat single file"
+ task :file, :path do |t, args|
+ format(args[:path])
+ end
+
+ desc "Reformat changes staged for commit"
+ task :cached do
+ `git diff --cached --name-only -- commands/`.split.each do |path|
+ format(path)
+ end
+ end
+
+ desc "Reformat everything"
+ task :all do
+ Dir["commands/*.md"].each do |path|
+ format(path)
+ end
+ end
+end
View
30 commands.json
@@ -233,7 +233,7 @@
"group": "transactions"
},
"DUMP": {
- "summary": "Return a serialized verison of the value stored at the specified key.",
+ "summary": "Return a serialized version of the value stored at the specified key.",
"complexity": "O(1) to access the key and additional O(N*M) to serialized it, where N is the number of Redis objects composing the value and M their average size. For small string values the time complexity is thus O(1)+O(1*M) where M is small, so simply O(1).",
"arguments": [
{
@@ -257,7 +257,7 @@
},
"EVAL": {
"summary": "Execute a Lua script server side",
- "complexity": "Looking up the script both with EVAL or EVALSHA is an O(1) business. The additional complexity is up to the script you execute.",
+ "complexity": "Depends on the script that is executed.",
"arguments": [
{
"name": "script",
@@ -281,6 +281,32 @@
"since": "2.6.0",
"group": "scripting"
},
+ "EVALSHA": {
+ "summary": "Execute a Lua script server side",
+ "complexity": "Depends on the script that is executed.",
+ "arguments": [
+ {
+ "name": "sha1",
+ "type": "string"
+ },
+ {
+ "name": "numkeys",
+ "type": "integer"
+ },
+ {
+ "name": "key",
+ "type": "key",
+ "multiple": true
+ },
+ {
+ "name": "arg",
+ "type": "string",
+ "multiple": true
+ }
+ ],
+ "since": "2.6.0",
+ "group": "scripting"
+ },
"EXEC": {
"summary": "Execute all commands issued after MULTI",
"since": "1.2.0",
View
67 commands/append.md
@@ -1,43 +1,56 @@
-If `key` already exists and is a string, this command appends the `value` at
-the end of the string. If `key` does not exist it is created and set as an
-empty string, so `APPEND` will be similar to `SET` in this special case.
+If `key` already exists and is a string, this command appends the `value` at the
+end of the string.
+If `key` does not exist it is created and set as an empty string, so `APPEND`
+will be similar to `SET` in this special case.
@return
@integer-reply: the length of the string after the append operation.
@examples
- @cli
- EXISTS mykey
- APPEND mykey "Hello"
- APPEND mykey " World"
- GET mykey
+```cli
+EXISTS mykey
+APPEND mykey "Hello"
+APPEND mykey " World"
+GET mykey
+```
-Pattern: Time series
----
+## Pattern: Time series
-the `APPEND` command can be used to create a very compact representation of
-a list of fixed-size samples, usually referred as *time series*.
+the `APPEND` command can be used to create a very compact representation of a
+list of fixed-size samples, usually referred as _time series_.
Every time a new sample arrives we can store it using the command
- APPEND timeseries "fixed-size sample"
+```
+APPEND timeseries "fixed-size sample"
+```
-Accessing to individual elements in the time serie is not hard:
+Accessing individual elements in the time series is not hard:
* `STRLEN` can be used in order to obtain the number of samples.
-* `GETRANGE` allows for random access of elements. If our time series have an associated time information we can easily implement a binary search to get range combining `GETRANGE` with the Lua scripting engine available in Redis 2.6.
+* `GETRANGE` allows for random access of elements.
+ If our time series have an associated time information we can easily implement
+ a binary search to get range combining `GETRANGE` with the Lua scripting
+ engine available in Redis 2.6.
* `SETRANGE` can be used to overwrite an existing time serie.
-The limitations of this pattern is that we are forced into an append-only mode of operation, there is no way to cut the time series to a given size easily because Redis currently lacks a command able to trim string objects. However the space efficiency of time series stored in this way is remarkable.
-
-Hint: it is possible to switch to a different key based on the current unix time, in this way it is possible to have just a relatively small amount of samples per key, to avoid dealing with very big keys, and to make this pattern more
-firendly to be distributed across many Redis instances.
-
-An example sampling the temperature of a sensor using fixed-size strings (using a binary format is better in real implementations).
-
- @cli
- APPEND ts "0043"
- APPEND ts "0035"
- GETRANGE ts 0 3
- GETRANGE ts 4 7
+The limitations of this pattern is that we are forced into an append-only mode
+of operation, there is no way to cut the time series to a given size easily
+because Redis currently lacks a command able to trim string objects.
+However the space efficiency of time series stored in this way is remarkable.
+
+Hint: it is possible to switch to a different key based on the current Unix
+time, in this way it is possible to have just a relatively small amount of
+samples per key, to avoid dealing with very big keys, and to make this pattern
+more friendly to be distributed across many Redis instances.
+
+An example sampling the temperature of a sensor using fixed-size strings (using
+a binary format is better in real implementations).
+
+```cli
+APPEND ts "0043"
+APPEND ts "0035"
+GETRANGE ts 0 3
+GETRANGE ts 4 7
+```
View
15 commands/auth.md
@@ -1,17 +1,16 @@
Request for authentication in a password protected Redis server.
-Redis can be instructed to require a password before allowing clients
-to execute commands. This is done using the `requirepass` directive in the
-configuration file.
+Redis can be instructed to require a password before allowing clients to execute
+commands.
+This is done using the `requirepass` directive in the configuration file.
-If `password` matches the password in the configuration file, the server replies with
-the `OK` status code and starts accepting commands.
+If `password` matches the password in the configuration file, the server replies
+with the `OK` status code and starts accepting commands.
Otherwise, an error is returned and the clients needs to try a new password.
**Note**: because of the high performance nature of Redis, it is possible to try
-a lot of passwords in parallel in very short time, so make sure to generate
-a strong and very long password so that this attack is infeasible.
+a lot of passwords in parallel in very short time, so make sure to generate a
+strong and very long password so that this attack is infeasible.
@return
@status-reply
-
View
28 commands/bgrewriteaof.md
@@ -1,15 +1,31 @@
-Instruct Redis to start an [Append Only File](/topics/persistence#append-only-file) rewrite process. The rewrite will create a small optimized version of the current Append Only File.
+Instruct Redis to start an [Append Only File][tpaof] rewrite process.
+The rewrite will create a small optimized version of the current Append Only
+File.
+
+[tpaof]: /topics/persistence#append-only-file
If `BGREWRITEAOF` fails, no data gets lost as the old AOF will be untouched.
-The rewrite will be only triggered by Redis if there is not already a background process doing persistence. Specifically:
+The rewrite will be only triggered by Redis if there is not already a background
+process doing persistence.
+Specifically:
+
+* If a Redis child is creating a snapshot on disk, the AOF rewrite is
+ _scheduled_ but not started until the saving child producing the RDB file
+ terminates.
+ In this case the `BGREWRITEAOF` will still return an OK code, but with an
+ appropriate message.
+ You can check if an AOF rewrite is scheduled looking at the `INFO` command
+ starting from Redis 2.6.
+* If an AOF rewrite is already in progress the command returns an error and no
+ AOF rewrite will be scheduled for a later time.
-* If a Redis child is creating a snapshot on disk, the AOF rewrite is *scheduled* but not started until the saving child producing the RDB file terminates. In this case the `BGREWRITEAOF` will still return an OK code, but with an appropriate message. You can check if an AOF rewrite is scheduled looking at the `INFO` command starting from Redis 2.6.
-* If an AOF rewrite is already in progress the command returns an error and no AOF rewrite will be scheduled for a later time.
+Since Redis 2.4 the AOF rewrite is automatically triggered by Redis, however the
+`BGREWRITEAOF` command can be used to trigger a rewrite at any time.
-Since Redis 2.4 the AOF rewrite is automatically triggered by Redis, however the `BGREWRITEAOF` command can be used to trigger a rewrite at any time.
+Please refer to the [persistence documentation][tp] for detailed information.
-Please check the documentation about [Redis Persistence](/topics/persistence#append-only-file) for more information.
+[tp]: /topics/persistence
@return
View
14 commands/bgsave.md
@@ -1,11 +1,13 @@
+Save the DB in background.
+The OK code is immediately returned.
+Redis forks, the parent continues to serve the clients, the child saves the DB
+on disk then exits.
+A client my be able to check if the operation succeeded using the `LASTSAVE`
+command.
+Please refer to the [persistence documentation][tp] for detailed information.
-Save the DB in background. The OK code is immediately returned.
-Redis forks, the parent continues to server the clients, the child
-saves the DB on disk then exit. A client my be able to check if the
-operation succeeded using the `LASTSAVE` command.
-
-Please refer to the [persistence documentation](/topics/persistence) for detailed information.
+[tp]: /topics/persistence
@return
View
77 commands/bitcount.md
@@ -1,15 +1,14 @@
Count the number of set bits (population counting) in a string.
-By default all the bytes contained in the string are examined. It is possible
-to specifiy the counting operation only in an interval passing the additional
-arguments *start* and *end*.
+By default all the bytes contained in the string are examined.
+It is possible to specify the counting operation only in an interval passing the
+additional arguments _start_ and _end_.
-Like for the `GETRANGE` command start and end can contain negative values
-in order to index bytes starting from the end of the string, where -1 is the
-last byte, -2 is the penultimate, and so forth.
+Like for the `GETRANGE` command start and end can contain negative values in
+order to index bytes starting from the end of the string, where -1 is the last
+byte, -2 is the penultimate, and so forth.
-Non existing keys are treated as empty strings, so the command will return
-zero.
+Non existing keys are treated as empty strings, so the command will return zero.
@return
@@ -19,43 +18,51 @@ The number of bits set to 1.
@examples
- @cli
- SET mykey "foobar"
- BITCOUNT mykey
- BITCOUNT mykey 0 0
- BITCOUNT mykey 1 1
+```cli
+SET mykey "foobar"
+BITCOUNT mykey
+BITCOUNT mykey 0 0
+BITCOUNT mykey 1 1
+```
-Pattern: real time metrics using bitmaps
----
+## Pattern: real time metrics using bitmaps
Bitmaps are a very space efficient representation of certain kinds of
-information. One example is a web application that needs the history
-of user visits, so that for instance it is possible to determine what
-users are good targets of beta features, or for any other purpose.
+information.
+One example is a web application that needs the history of user visits, so that
+for instance it is possible to determine what users are good targets of beta
+features, or for any other purpose.
-Using the `SETBIT` command this is trivial to accomplish, identifying every
-day with a small progressive integer. For instance day 0 is the first day
-the application was put online, day 1 the next day, and so forth.
+Using the `SETBIT` command this is trivial to accomplish, identifying every day
+with a small progressive integer.
+For instance day 0 is the first day the application was put online, day 1 the
+next day, and so forth.
-Every time an user performs a page view, the application can register that
-in the current day the user visited the web site using the `SETBIT` command
-setting the bit corresponding to the current day.
+Every time an user performs a page view, the application can register that in
+the current day the user visited the web site using the `SETBIT` command setting
+the bit corresponding to the current day.
-Later it will be trivial to know the number of single days the user visited
-the web site simply calling the `BITCOUNT` command against the bitmap.
+Later it will be trivial to know the number of single days the user visited the
+web site simply calling the `BITCOUNT` command against the bitmap.
A similar pattern where user IDs are used instead of days is described
-in the article [Fast easy realtime metrics usign Redis bitmaps](http://blog.getspool.com/2011/11/29/fast-easy-realtime-metrics-using-redis-bitmaps/).
+in the article called "[Fast easy realtime metrics using Redis
+bitmaps][hbgc212fermurb]".
-Performance considerations
----
+[hbgc212fermurb]: http://blog.getspool.com/2011/11/29/fast-easy-realtime-metrics-using-redis-bitmaps
-In the above example of counting days, even after 10 years the application
-is online we still have just `365*10` bits of data per user, that is
-just 456 bytes per user. With this amount of data `BITCOUNT` is still as fast
-as any other O(1) Redis command like `GET` or `INCR`.
+## Performance considerations
+
+In the above example of counting days, even after 10 years the application is
+online we still have just `365*10` bits of data per user, that is just 456 bytes
+per user.
+With this amount of data `BITCOUNT` is still as fast as any other O(1) Redis
+command like `GET` or `INCR`.
When the bitmap is big, there are two alternatives:
-+ Taking a separated key that is incremented every time the bitmap is modified. This can be very efficient and atomic using a small Redis Lua script.
-+ Running the bitmap incrementally using the `BITCOUNT` *start* and *end* optional parameters, accumulating the results client-side, and optionally caching the result into a key.
+* Taking a separated key that is incremented every time the bitmap is modified.
+ This can be very efficient and atomic using a small Redis Lua script.
+* Running the bitmap incrementally using the `BITCOUNT` _start_ and _end_
+ optional parameters, accumulating the results client-side, and optionally
+ caching the result into a key.
View
65 commands/bitop.md
@@ -1,24 +1,24 @@
-Perform a bitwise operation between multiple keys (containing string
-values) and store the result in the destionation key.
+Perform a bitwise operation between multiple keys (containing string values) and
+store the result in the destination key.
-The `BITOP` command supports four bitwise operations: **AND**, **OR**, **XOR** and **NOT**, thus the valid forms to call the command are:
+The `BITOP` command supports four bitwise operations: **AND**, **OR**, **XOR**
+and **NOT**, thus the valid forms to call the command are:
-+ BITOP AND *destkey srckey1 srckey2 srckey3 ... srckeyN*
-+ BITOP OR *destkey srckey1 srckey2 srckey3 ... srckeyN*
-+ BITOP XOR *destkey srckey1 srckey2 srckey3 ... srckeyN*
-+ BITOP NOT *destkey srckey*
+* BITOP AND _destkey srckey1 srckey2 srckey3 ... srckeyN_
+* BITOP OR _destkey srckey1 srckey2 srckey3 ... srckeyN_
+* BITOP XOR _destkey srckey1 srckey2 srckey3 ... srckeyN_
+* BITOP NOT _destkey srckey_
As you can see **NOT** is special as it only takes an input key, because it
-performs invertion of bits so it only makes sense as an unary operator.
+performs inversion of bits so it only makes sense as an unary operator.
-The result of the operation is always stored at *destkey*.
+The result of the operation is always stored at _destkey_.
-Handling of strings with different lengths
----
+## Handling of strings with different lengths
-When an operation is performed between strings having different lengths, all
-the strings shorter than the longest string in the set are treated as if
-they were zero-padded up to the length of the longest string.
+When an operation is performed between strings having different lengths, all the
+strings shorter than the longest string in the set are treated as if they were
+zero-padded up to the length of the longest string.
The same holds true for non-existing keys, that are considered as a stream of
zero bytes up to the length of the longest string.
@@ -27,30 +27,35 @@ zero bytes up to the length of the longest string.
@integer-reply
-The size of the string stored into the destination key, that is equal to the size of the longest input string.
+The size of the string stored into the destination key, that is equal to the
+size of the longest input string.
@examples
- @cli
- SET key1 "foobar"
- SET key2 "abcdef"
- BITOP AND dest key1 key2
- GET dest
+```cli
+SET key1 "foobar"
+SET key2 "abcdef"
+BITOP AND dest key1 key2
+GET dest
+```
-Pattern: real time metrics using bitmaps
----
+## Pattern: real time metrics using bitmaps
-`BITOP` is a good complement to the pattern documented in the `BITCOUNT` command documentation. Different bitmaps can be combined in order to obtain a target
-bitmap where to perform the population counting operation.
+`BITOP` is a good complement to the pattern documented in the `BITCOUNT` command
+documentation.
+Different bitmaps can be combined in order to obtain a target bitmap where to
+perform the population counting operation.
-See the article [Fast easy realtime metrics usign Redis bitmaps](http://blog.getspool.com/2011/11/29/fast-easy-realtime-metrics-using-redis-bitmaps/) for an interesting use cases.
+See the article called "[Fast easy realtime metrics using Redis
+bitmaps][hbgc212fermurb]" for an interesting use cases.
-Performance considerations
----
+[hbgc212fermurb]: http://blog.getspool.com/2011/11/29/fast-easy-realtime-metrics-using-redis-bitmaps
+
+## Performance considerations
`BITOP` is a potentially slow command as it runs in O(N) time.
Care should be taken when running it against long input strings.
-For real time metrics and statistics involving large inputs a good approach
-is to use a slave (with read-only option disabled) where to perform the
-bit-wise operations without blocking the master instance.
+For real time metrics and statistics involving large inputs a good approach is
+to use a slave (with read-only option disabled) where to perform the bit-wise
+operations without blocking the master instance.
View
116 commands/blpop.md
@@ -1,102 +1,112 @@
-`BLPOP` is a blocking list pop primitive. It is the blocking version of `LPOP`
-because it blocks the connection when there are no elements to pop from any of
-the given lists. An element is popped from the head of the first list that is
-non-empty, with the given keys being checked in the order that they are given.
+`BLPOP` is a blocking list pop primitive.
+It is the blocking version of `LPOP` because it blocks the connection when there
+are no elements to pop from any of the given lists.
+An element is popped from the head of the first list that is non-empty, with the
+given keys being checked in the order that they are given.
## Non-blocking behavior
-When `BLPOP` is called, if at least one of the specified keys contain a
+When `BLPOP` is called, if at least one of the specified keys contains a
non-empty list, an element is popped from the head of the list and returned to
the caller together with the `key` it was popped from.
-Keys are checked in the order that they are given. Let's say that the key
-`list1` doesn't exist and `list2` and `list3` hold non-empty lists. Consider
-the following command:
+Keys are checked in the order that they are given.
+Let's say that the key `list1` doesn't exist and `list2` and `list3` hold
+non-empty lists.
+Consider the following command:
- BLPOP list1 list2 list3 0
+```
+BLPOP list1 list2 list3 0
+```
`BLPOP` guarantees to return an element from the list stored at `list2` (since
it is the first non empty list when checking `list1`, `list2` and `list3` in
that order).
## Blocking behavior
-If none of the specified keys exist, `BLPOP` blocks
-the connection until another client performs an `LPUSH` or `RPUSH` operation
-against one of the keys.
+If none of the specified keys exist, `BLPOP` blocks the connection until another
+client performs an `LPUSH` or `RPUSH` operation against one of the keys.
Once new data is present on one of the lists, the client returns with the name
of the key unblocking it and the popped value.
-When `BLPOP` causes a client to block and a non-zero timeout is specified, the
-client will unblock returning a `nil` multi-bulk value when the specified
+When `BLPOP` causes a client to block and a non-zero timeout is specified,
+the client will unblock returning a `nil` multi-bulk value when the specified
timeout has expired without a push operation against at least one of the
specified keys.
-The timeout argument is interpreted as an integer value. A timeout of zero can
-be used to block indefinitely.
+The timeout argument is interpreted as an integer value.
+A timeout of zero can be used to block indefinitely.
## Multiple clients blocking for the same keys
-Multiple clients can block for the same key. They are put into
-a queue, so the first to be served will be the one that started to wait
-earlier, in a first-`!BLPOP` first-served fashion.
+Multiple clients can block for the same key.
+They are put into a queue, so the first to be served will be the one that
+started to wait earlier, in a first- `!BLPOP` first-served fashion.
-## `!BLPOP` inside a `!MULTI`/`!EXEC` transaction
+## `!BLPOP` inside a `!MULTI` / `!EXEC` transaction
`BLPOP` can be used with pipelining (sending multiple commands and reading the
-replies in batch), but it does not make sense to use `BLPOP` inside a
-`MULTI`/`EXEC` block. This would require blocking the entire server in order to
-execute the block atomically, which in turn does not allow other clients to
-perform a push operation.
+replies in batch), but it does not make sense to use `BLPOP` inside a `MULTI` /
+`EXEC` block.
+This would require blocking the entire server in order to execute the block
+atomically, which in turn does not allow other clients to perform a push
+operation.
-The behavior of `BLPOP` inside `MULTI`/`EXEC` when the list is empty is to
+The behavior of `BLPOP` inside `MULTI` / `EXEC` when the list is empty is to
return a `nil` multi-bulk reply, which is the same thing that happens when the
-timeout is reached. If you like science fiction, think of time flowing at
-infinite speed inside a `MULTI`/`EXEC` block.
+timeout is reached.
+If you like science fiction, think of time flowing at infinite speed inside a
+`MULTI` / `EXEC` block.
@return
@multi-bulk-reply: specifically:
* A `nil` multi-bulk when no element could be popped and the timeout expired.
-* A two-element multi-bulk with the first element being the name of the key where an element
- was popped and the second element being the value of the popped element.
+* A two-element multi-bulk with the first element being the name of the key
+ where an element was popped and the second element being the value of the
+ popped element.
@examples
- redis> DEL list1 list2
- (integer) 0
- redis> RPUSH list1 a b c
- (integer) 3
- redis> BLPOP list1 list2 0
- 1) "list1"
- 2) "a"
+```
+redis> DEL list1 list2
+(integer) 0
+redis> RPUSH list1 a b c
+(integer) 3
+redis> BLPOP list1 list2 0
+1) "list1"
+2) "a"
+```
## Pattern: Event notification
Using blocking list operations it is possible to mount different blocking
-primitives. For instance for some application you may need to block
-waiting for elements into a Redis Set, so that as far as a new element is
-added to the Set, it is possible to retrieve it without resort to polling.
-This would require a blocking version of `SPOP` that is
-not available, but using blocking list operations we can easily accomplish
-this task.
+primitives.
+For instance for some application you may need to block waiting for elements
+into a Redis Set, so that as far as a new element is added to the Set, it is
+possible to retrieve it without resort to polling.
+This would require a blocking version of `SPOP` that is not available, but using
+blocking list operations we can easily accomplish this task.
The consumer will do:
- LOOP forever
- WHILE SPOP(key) returns elements
- ... process elements ...
- END
- BRPOP helper_key
+```
+LOOP forever
+ WHILE SPOP(key) returns elements
+ ... process elements ...
END
+ BRPOP helper_key
+END
+```
While in the producer side we'll use simply:
- MULTI
- SADD key element
- LPUSH helper_key x
- EXEC
-
-
+```
+MULTI
+SADD key element
+LPUSH helper_key x
+EXEC
+```
View
40 commands/brpop.md
@@ -1,28 +1,32 @@
-`BRPOP` is a blocking list pop primitive. It is the blocking version of
-`RPOP` because it blocks the connection when there are no
-elements to pop from any of the given lists. An element is popped from the
-tail of the first list that is non-empty, with the given keys being checked
-in the order that they are given.
+`BRPOP` is a blocking list pop primitive.
+It is the blocking version of `RPOP` because it blocks the connection when there
+are no elements to pop from any of the given lists.
+An element is popped from the tail of the first list that is non-empty, with the
+given keys being checked in the order that they are given.
-See the [BLPOP documentation](/commands/blpop) for the exact semantics, since
-`BRPOP` is identical to `BLPOP` with the only difference
-being that it pops elements from the tail of a list instead of popping from the
-head.
+See the [BLPOP documentation][cb] for the exact semantics, since `BRPOP` is
+identical to `BLPOP` with the only difference being that it pops elements from
+the tail of a list instead of popping from the head.
+
+[cb]: /commands/blpop
@return
@multi-bulk-reply: specifically:
* A `nil` multi-bulk when no element could be popped and the timeout expired.
-* A two-element multi-bulk with the first element being the name of the key where an element
- was popped and the second element being the value of the popped element.
+* A two-element multi-bulk with the first element being the name of the key
+ where an element was popped and the second element being the value of the
+ popped element.
@examples
- redis> DEL list1 list2
- (integer) 0
- redis> RPUSH list1 a b c
- (integer) 3
- redis> BRPOP list1 list2 0
- 1) "list1"
- 2) "c"
+```
+redis> DEL list1 list2
+(integer) 0
+redis> RPUSH list1 a b c
+(integer) 3
+redis> BRPOP list1 list2 0
+1) "list1"
+2) "c"
+```
View
17 commands/brpoplpush.md
@@ -1,21 +1,20 @@
`BRPOPLPUSH` is the blocking variant of `RPOPLPUSH`.
-When `source` contains elements, this command behaves exactly like
-`RPOPLPUSH`. When `source` is empty, Redis will block
-the connection until another client pushes to it or until `timeout` is reached. A `timeout` of zero can be used to block indefinitely.
+When `source` contains elements, this command behaves exactly like `RPOPLPUSH`.
+When `source` is empty, Redis will block the connection until another client
+pushes to it or until `timeout` is reached.
+A `timeout` of zero can be used to block indefinitely.
See `RPOPLPUSH` for more information.
@return
-@bulk-reply: the element being popped from `source` and pushed to
-`destination`. If `timeout` is reached, a @nil-reply is returned.
+@bulk-reply: the element being popped from `source` and pushed to `destination`.
+If `timeout` is reached, a @nil-reply is returned.
-Pattern: Reliable queue
----
+## Pattern: Reliable queue
Please see the pattern description in the `RPOPLPUSH` documentation.
-Pattern: Circular list
----
+## Pattern: Circular list
Please see the pattern description in the `RPOPLPUSH` documentation.
View
70 commands/config get.md
@@ -1,40 +1,52 @@
The `CONFIG GET` command is used to read the configuration parameters of a
-running Redis server. Not all the configuration parameters are
-supported in Redis 2.4, while Redis 2.6 can read the whole configuration of
-a server using this command.
-
-The symmetric command used to alter the configuration at run time is
-`CONFIG SET`.
-
-`CONFIG GET` takes a single argument, that is glob style pattern. All the
-configuration parameters matching this parameter are reported as a
-list of key-value pairs. Example:
-
- redis> config get *max-*-entries*
- 1) "hash-max-zipmap-entries"
- 2) "512"
- 3) "list-max-ziplist-entries"
- 4) "512"
- 5) "set-max-intset-entries"
- 6) "512"
-
-You can obtain a list of all the supported configuration parameters typing
+running Redis server.
+Not all the configuration parameters are supported in Redis 2.4, while Redis 2.6
+can read the whole configuration of a server using this command.
+
+The symmetric command used to alter the configuration at run time is `CONFIG
+SET`.
+
+`CONFIG GET` takes a single argument, which is a glob-style pattern.
+All the configuration parameters matching this parameter are reported as a list
+of key-value pairs.
+Example:
+
+```
+redis> config get *max-*-entries*
+1) "hash-max-zipmap-entries"
+2) "512"
+3) "list-max-ziplist-entries"
+4) "512"
+5) "set-max-intset-entries"
+6) "512"
+```
+
+You can obtain a list of all the supported configuration parameters by typing
`CONFIG GET *` in an open `redis-cli` prompt.
All the supported parameters have the same meaning of the equivalent
-configuration parameter used in the [redis.conf](http://github.com/antirez/redis/raw/2.2/redis.conf) file, with the following important differences:
+configuration parameter used in the [redis.conf][hgcarr22rc] file, with the
+following important differences:
-* Where bytes or other quantities are specified, it is not possible to use the redis.conf abbreviated form (10k 2gb ... and so forth), everything should be specified as a well formed 64 bit integer, in the base unit of the configuration directive.
-* The save parameter is a single string of space separated integers. Every pair of integers represent a seconds/modifications threshold.
+[hgcarr22rc]: http://github.com/antirez/redis/raw/2.2/redis.conf
-For instance what in redis.conf looks like:
+* Where bytes or other quantities are specified, it is not possible to use
+ the `redis.conf` abbreviated form (10k 2gb ... and so forth), everything
+ should be specified as a well-formed 64-bit integer, in the base unit of the
+ configuration directive.
+* The save parameter is a single string of space-separated integers.
+ Every pair of integers represent a seconds/modifications threshold.
- save 900 1
- save 300 10
+For instance what in `redis.conf` looks like:
-that means, save after 900 seconds if there is at least 1 change to the
-dataset, and after 300 seconds if there are at least 10 changes to the
-datasets, will be reported by `CONFIG GET` as "900 1 300 10".
+```
+save 900 1
+save 300 10
+```
+
+that means, save after 900 seconds if there is at least 1 change to the dataset,
+and after 300 seconds if there are at least 10 changes to the datasets, will be
+reported by `CONFIG GET` as "900 1 300 10".
@return
View
68 commands/config set.md
@@ -1,44 +1,56 @@
-The `CONFIG SET` command is used in order to reconfigure the server at runtime
-without the need to restart Redis. You can change both trivial parameters or
-switch from one to another persistence option using this command.
+The `CONFIG SET` command is used in order to reconfigure the server at run time
+without the need to restart Redis.
+You can change both trivial parameters or switch from one to another persistence
+option using this command.
-The list of configuration parameters supported by `CONFIG SET` can be
-obtained issuing a `CONFIG GET *` command, that is the symmetrical command
-used to obtain information about the configuration of a running
-Redis instance.
+The list of configuration parameters supported by `CONFIG SET` can be obtained
+issuing a `CONFIG GET *` command, that is the symmetrical command used to obtain
+information about the configuration of a running Redis instance.
All the configuration parameters set using `CONFIG SET` are immediately loaded
-by Redis that will start acting as specified starting from the next command
-executed.
+by Redis and will take effect starting with the next command executed.
All the supported parameters have the same meaning of the equivalent
-configuration parameter used in the [redis.conf](http://github.com/antirez/redis/raw/2.2/redis.conf) file, with the following important differences:
+configuration parameter used in the [redis.conf][hgcarr22rc] file, with the
+following important differences:
-* Where bytes or other quantities are specified, it is not possible to use the redis.conf abbreviated form (10k 2gb ... and so forth), everything should be specified as a well formed 64 bit integer, in the base unit of the configuration directive.
-* The save parameter is a single string of space separated integers. Every pair of integers represent a seconds/modifications threshold.
+[hgcarr22rc]: http://github.com/antirez/redis/raw/2.2/redis.conf
-For instance what in redis.conf looks like:
+* Where bytes or other quantities are specified, it is not possible to use
+ the `redis.conf` abbreviated form (10k 2gb ... and so forth), everything
+ should be specified as a well-formed 64-bit integer, in the base unit of the
+ configuration directive.
+* The save parameter is a single string of space-separated integers.
+ Every pair of integers represent a seconds/modifications threshold.
- save 900 1
- save 300 10
+For instance what in `redis.conf` looks like:
-that means, save after 900 seconds if there is at least 1 change to the
-dataset, and after 300 seconds if there are at least 10 changes to the
-datasets, should be set using `CONFIG SET` as "900 1 300 10".
+```
+save 900 1
+save 300 10
+```
-It is possible to switch persistence form .rdb snapshotting to append only file
-(and the other way around) using the `CONFIG SET` command. For more information
-about how to do that please check [persistence page](/topics/persistence).
+that means, save after 900 seconds if there is at least 1 change to the dataset,
+and after 300 seconds if there are at least 10 changes to the datasets, should
+be set using `CONFIG SET` as "900 1 300 10".
-In general what you should know is that setting the *appendonly* parameter to
-*yes* will start a background process to save the initial append only file
+It is possible to switch persistence from RDB snapshotting to append-only file
+(and the other way around) using the `CONFIG SET` command.
+For more information about how to do that please check the [persistence
+page][tp].
+
+[tp]: /topics/persistence
+
+In general what you should know is that setting the `appendonly` parameter to
+`yes` will start a background process to save the initial append-only file
(obtained from the in memory data set), and will append all the subsequent
-commands on the append only file, thus obtaining exactly the same effect of
-a Redis server that started with AOF turned on since the start.
+commands on the append-only file, thus obtaining exactly the same effect of a
+Redis server that started with AOF turned on since the start.
-You can have both the AOF enabled with .rdb snapshotting if you want, the
-two options are not mutually exclusive.
+You can have both the AOF enabled with RDB snapshotting if you want, the two
+options are not mutually exclusive.
@return
-@status-reply: `OK` when the configuration was set properly. Otherwise an error is returned.
+@status-reply: `OK` when the configuration was set properly.
+Otherwise an error is returned.
View
4 commands/dbsize.md
@@ -1,6 +1,4 @@
-
-
-Return the number of keys in the currently selected database.
+Return the number of keys in the currently-selected database.
@return
View
22 commands/decr.md
@@ -1,20 +1,20 @@
Decrements the number stored at `key` by one.
-If the key does not exist, it is set to `0` before performing the operation. An
-error is returned if the key contains a value of the wrong type or contains a
-string that is not representable as integer. This operation is limited to **64
-bit signed integers**.
+If the key does not exist, it is set to `0` before performing the operation.
+An error is returned if the key contains a value of the wrong type or contains a
+string that can not be represented as integer.
+This operation is limited to **64 bit signed integers**.
-See `INCR` for extra information on increment/decrement
-operations.
+See `INCR` for extra information on increment/decrement operations.
@return
@integer-reply: the value of `key` after the decrement
@examples
- @cli
- SET mykey "10"
- DECR mykey
- SET mykey "234293482390480948029348230948"
- DECR mykey
+```cli
+SET mykey "10"
+DECR mykey
+SET mykey "234293482390480948029348230948"
+DECR mykey
+```
View
16 commands/decrby.md
@@ -1,8 +1,8 @@
Decrements the number stored at `key` by `decrement`.
-If the key does not exist, it is set to `0` before performing the operation. An
-error is returned if the key contains a value of the wrong type or contains a
-string that is not representable as integer. This operation is limited to 64
-bit signed integers.
+If the key does not exist, it is set to `0` before performing the operation.
+An error is returned if the key contains a value of the wrong type or contains a
+string that can not be represented as integer.
+This operation is limited to 64 bit signed integers.
See `INCR` for extra information on increment/decrement operations.
@@ -12,7 +12,7 @@ See `INCR` for extra information on increment/decrement operations.
@examples
- @cli
- SET mykey "10"
- DECRBY mykey 5
-
+```cli
+SET mykey "10"
+DECRBY mykey 5
+```
View
13 commands/del.md
@@ -1,13 +1,14 @@
-Removes the specified keys. A key is ignored if it does not exist.
+Removes the specified keys.
+A key is ignored if it does not exist.
@return
@integer-reply: The number of keys that were removed.
@examples
- @cli
- SET key1 "Hello"
- SET key2 "World"
- DEL key1 key2 key3
-
+```cli
+SET key1 "Hello"
+SET key2 "World"
+DEL key1 key2 key3
+```
View
7 commands/discard.md
@@ -1,6 +1,7 @@
-Flushes all previously queued commands in a
-[transaction](/topics/transactions) and restores the connection state to
-normal.
+Flushes all previously queued commands in a [transaction][tt] and restores the
+connection state to normal.
+
+[tt]: /topics/transactions
If `WATCH` was used, `DISCARD` unwatches all keys.
View
32 commands/dump.md
@@ -1,12 +1,23 @@
-Serialize the value stored at key in a Redis-specific format and return it to the user. The returned value can be synthesized back into a Redis key using the `RESTORE` command.
-
-The serialization format is opaque and non-standard, however it has a few semantical characteristics:
-
-* It contains a 64bit checksum that is used to make sure errors will be detected. The `RESTORE` command makes sure to check the checksum before synthesizing a key using the serialized value.
+Serialize the value stored at key in a Redis-specific format and return it to
+the user.
+The returned value can be synthesized back into a Redis key using the `RESTORE`
+command.
+
+The serialization format is opaque and non-standard, however it has a few
+semantical characteristics:
+
+* It contains a 64-bit checksum that is used to make sure errors will be
+ detected.
+ The `RESTORE` command makes sure to check the checksum before synthesizing a
+ key using the serialized value.
* Values are encoded in the same format used by RDB.
-* An RDB version is encoded inside the serialized value, so that different Redis versions with incompatible RDB formats will refuse to process the serialized value.
+* An RDB version is encoded inside the serialized value, so that different Redis
+ versions with incompatible RDB formats will refuse to process the serialized
+ value.
-The serialized value does NOT contain expire information. In order to capture the time to live of the current value the `PTTL` command should be used.
+The serialized value does NOT contain expire information.
+In order to capture the time to live of the current value the `PTTL` command
+should be used.
If `key` does not exist a nil bulk reply is returned.
@@ -16,6 +27,7 @@ If `key` does not exist a nil bulk reply is returned.
@examples
- @cli
- SET mykey 10
- DUMP mykey
+```cli
+SET mykey 10
+DUMP mykey
+```
View
6 commands/echo.md
@@ -6,6 +6,6 @@ Returns `message`.
@examples
- @cli
- ECHO "Hello World!"
-
+```cli
+ECHO "Hello World!"
+```
View
730 commands/eval.md
@@ -1,35 +1,37 @@
-Introduction to EVAL
----
+## Introduction to EVAL
`EVAL` and `EVALSHA` are used to evaluate scripts using the Lua interpreter
built into Redis starting from version 2.6.0.
-The first argument of `EVAL` is a Lua 5.1 script. The script does not need
-to define a Lua function (and should not). It is just a Lua program that will run in the context of the Redis server.
+The first argument of `EVAL` is a Lua 5.1 script.
+The script does not need to define a Lua function (and should not).
+It is just a Lua program that will run in the context of the Redis server.
-The second argument of `EVAL` is the number of arguments that follows
-the script (starting from the third argument) that represent Redis key names.
-This arguments can be accessed by Lua using the `KEYS` global variable in
-the form of a one-based array (so `KEYS[1]`, `KEYS[2]`, ...).
+The second argument of `EVAL` is the number of arguments that follows the script
+(starting from the third argument) that represent Redis key names.
+This arguments can be accessed by Lua using the `KEYS` global variable in the
+form of a one-based array (so `KEYS[1]`, `KEYS[2]`, ...).
-All the additional arguments should not represent key names and can
-be accessed by Lua using the `ARGV` global variable, very similarly to
-what happens with keys (so `ARGV[1]`, `ARGV[2]`, ...).
+All the additional arguments should not represent key names and can be accessed
+by Lua using the `ARGV` global variable, very similarly to what happens with
+keys (so `ARGV[1]`, `ARGV[2]`, ...).
The following example should clarify what stated above:
- > eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second
- 1) "key1"
- 2) "key2"
- 3) "first"
- 4) "second"
+```
+> eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second
+1) "key1"
+2) "key2"
+3) "first"
+4) "second"
+```
-Note: as you can see Lua arrays are returned as Redis multi bulk
-replies, that is a Redis return type that your client library will
-likely convert into an Array type in your programming language.
+Note: as you can see Lua arrays are returned as Redis multi bulk replies, that
+is a Redis return type that your client library will likely convert into an
+Array type in your programming language.
-It is possible to call Redis commands from a Lua script using two different
-Lua functions:
+It is possible to call Redis commands from a Lua script using two different Lua
+functions:
* `redis.call()`
* `redis.pcall()`
@@ -40,44 +42,52 @@ error that in turn will force `EVAL` to return an error to the command caller,
while `redis.pcall` will trap the error returning a Lua table representing the
error.
-The arguments of the `redis.call()` and `redis.pcall()` functions are simply
-all the arguments of a well formed Redis command:
+The arguments of the `redis.call()` and `redis.pcall()` functions are simply all
+the arguments of a well formed Redis command:
- > eval "return redis.call('set','foo','bar')" 0
- OK
+```
+> eval "return redis.call('set','foo','bar')" 0
+OK
+```
The above script actually sets the key `foo` to the string `bar`.
-However it violates the `EVAL` command semantics as all the keys that the
-script uses should be passed using the KEYS array, in the following way:
+However it violates the `EVAL` command semantics as all the keys that the script
+uses should be passed using the KEYS array, in the following way:
- > eval "return redis.call('set',KEYS[1],'bar')" 1 foo
- OK
+```
+> eval "return redis.call('set',KEYS[1],'bar')" 1 foo
+OK
+```
-The reason for passing keys in the proper way is that, before of `EVAL` all
-the Redis commands could be analyzed before execution in order to
-establish what are the keys the command will operate on.
+The reason for passing keys in the proper way is that, before `EVAL` all the
+Redis commands could be analyzed before execution in order to establish what
+keys the command will operate on.
In order for this to be true for `EVAL` also keys must be explicit.
This is useful in many ways, but especially in order to make sure Redis Cluster
-is able to forward your request to the appropriate cluster node (Redis
-Cluster is a work in progress, but the scripting feature was designed
-in order to play well with it). However this rule is not enforced in order to provide the user with opportunities to abuse the Redis single instance configuration, at the cost of writing scripts not compatible with Redis Cluster.
+is able to forward your request to the appropriate cluster node (Redis Cluster
+is a work in progress, but the scripting feature was designed in order to play
+well with it).
+However this rule is not enforced in order to provide the user with
+opportunities to abuse the Redis single instance configuration, at the cost of
+writing scripts not compatible with Redis Cluster.
-Lua scripts can return a value, that is converted from the Lua type to the Redis protocol using a set of conversion rules.
+Lua scripts can return a value, that is converted from the Lua type to the Redis
+protocol using a set of conversion rules.
-Conversion between Lua and Redis data types
----
+## Conversion between Lua and Redis data types
-Redis return values are converted into Lua data types when Lua calls a
-Redis command using call() or pcall(). Similarly Lua data types are
-converted into Redis protocol when a Lua script returns some value, so that
-scripts can control what `EVAL` will reply to the client.
+Redis return values are converted into Lua data types when Lua calls a Redis
+command using call() or pcall().
+Similarly Lua data types are converted into the Redis protocol when a Lua script
+returns a value, so that scripts can control what `EVAL` will return to the
+client.
-This conversion between data types is designed in a way that if
-a Redis type is converted into a Lua type, and then the result is converted
-back into a Redis type, the result is the same as of the initial value.
+This conversion between data types is designed in a way that if a Redis type is
+converted into a Lua type, and then the result is converted back into a Redis
+type, the result is the same as of the initial value.
-In other words there is a one to one conversion between Lua and Redis types.
+In other words there is a one-to-one conversion between Lua and Redis types.
The following table shows you all the conversions rules:
**Redis to Lua** conversion table.
@@ -98,313 +108,343 @@ The following table shows you all the conversions rules:
* Lua table with a single `err` field -> Redis error reply
* Lua boolean false -> Redis Nil bulk reply.
-There is an additional Lua to Redis conversion rule that has no corresponding
+There is an additional Lua-to-Redis conversion rule that has no corresponding
Redis to Lua conversion rule:
- * Lua boolean true -> Redis integer reply with value of 1.
+* Lua boolean true -> Redis integer reply with value of 1.
-The followings are a few conversion examples:
+Here are a few conversion examples:
- > eval "return 10" 0
- (integer) 10
+```
+> eval "return 10" 0
+(integer) 10
- > eval "return {1,2,{3,'Hello World!'}}" 0
- 1) (integer) 1
- 2) (integer) 2
- 3) 1) (integer) 3
- 2) "Hello World!"
+> eval "return {1,2,{3,'Hello World!'}}" 0
+1) (integer) 1
+2) (integer) 2
+3) 1) (integer) 3
+ 2) "Hello World!"
- > eval "return redis.call('get','foo')" 0
- "bar"
+> eval "return redis.call('get','foo')" 0
+"bar"
+```
-The last example shows how it is possible to directly return from Lua
-the return value of `redis.call()` and `redis.pcall()` with the result of
-returning exactly what the called command would return if called directly.
+The last example shows how it is possible to receive the exact return value of
+`redis.call()` or `redis.pcall()` from Lua that would be returned if the command
+was called directly.
-Atomicity of scripts
----
+## Atomicity of scripts
-Redis uses the same Lua interpreter to run all the commands. Also Redis
-guarantees that a script is executed in an atomic way: no other script
-or Redis command will be executed while a script is being executed.
+Redis uses the same Lua interpreter to run all the commands.
+Also Redis guarantees that a script is executed in an atomic way: no other
+script or Redis command will be executed while a script is being executed.
This semantics is very similar to the one of `MULTI` / `EXEC`.
-From the point of view of all the other clients the effects of a script
-are either still not visible or already completed.
+From the point of view of all the other clients the effects of a script are
+either still not visible or already completed.
However this also means that executing slow scripts is not a good idea.
-It is not hard to create fast scripts, as the script overhead is very low,
-but if you are going to use slow scripts you should be aware that while the
-script is running no other client can execute commands since the server
-is busy.
+It is not hard to create fast scripts, as the script overhead is very low, but
+if you are going to use slow scripts you should be aware that while the script
+is running no other client can execute commands since the server is busy.
-Error handling
----
+## Error handling
-As already stated calls to `redis.call()` resulting into a Redis command error
-will stop the execution of the script and will return that error back, in a
-way that makes it obvious that the error was generated by a script:
+As already stated, calls to `redis.call()` resulting in a Redis command error
+will stop the execution of the script and will return the error, in a way that
+makes it obvious that the error was generated by a script:
- > del foo
- (integer) 1
- > lpush foo a
- (integer) 1
- > eval "return redis.call('get','foo')" 0
- (error) ERR Error running script (call to f_6b1bf486c81ceb7edf3c093f4c48582e38c0e791): ERR Operation against a key holding the wrong kind of value
+```
+> del foo
+(integer) 1
+> lpush foo a
+(integer) 1
+> eval "return redis.call('get','foo')" 0
+(error) ERR Error running script (call to f_6b1bf486c81ceb7edf3c093f4c48582e38c0e791): ERR Operation against a key holding the wrong kind of value
+```
-Using the `redis.pcall()` command no error is raised, but an error object
-is returned in the format specified above (as a Lua table with an `err`
-field). The user can later return this exact error to the user just returning
-the error object returned by `redis.pcall()`.
+Using the `redis.pcall()` command no error is raised, but an error object is
+returned in the format specified above (as a Lua table with an `err` field).
+The script can pass the exact error to the user by returning the error object
+returned by `redis.pcall()`.
-Bandwidth and EVALSHA
----
+## Bandwidth and EVALSHA
The `EVAL` command forces you to send the script body again and again.
Redis does not need to recompile the script every time as it uses an internal
-caching mechanism, however paying the cost of the additional bandwidth may
-not be optimal in many contexts.
+caching mechanism, however paying the cost of the additional bandwidth may not
+be optimal in many contexts.
-On the other hand defining commands using a special command or via `redis.conf`
+On the other hand, defining commands using a special command or via `redis.conf`
would be a problem for a few reasons:
-* Different instances may have different versions of a command implementation.
+* Different instances may have different versions of a command implementation.
-* Deployment is hard if there is to make sure all the instances contain a given command, especially in a distributed environment.
+* Deployment is hard if there is to make sure all the instances contain a
+ given command, especially in a distributed environment.
-* Reading an application code the full semantic could not be clear since the application would call commands defined server side.
+* Reading an application code the full semantic could not be clear since the
+ application would call commands defined server side.
-In order to avoid the above three problems and at the same time don't incur
-in the bandwidth penalty, Redis implements the `EVALSHA` command.
+In order to avoid these problems while avoiding the bandwidth penalty, Redis
+implements the `EVALSHA` command.
-`EVALSHA` works exactly as `EVAL`, but instead of having a script as first argument it has the SHA1 sum of a script. The behavior is the following:
+`EVALSHA` works exactly like `EVAL`, but instead of having a script as the first
+argument it has the SHA1 digest of a script.
+The behavior is the following:
-* If the server still remembers a script whose SHA1 sum was the one
-specified, the script is executed.
+* If the server still remembers a script with a matching SHA1 digest, the
+ script is executed.
-* If the server does not remember a script with this SHA1 sum, a special
-error is returned that will tell the client to use `EVAL` instead.
+* If the server does not remember a script with this SHA1 digest, a special
+ error is returned telling the client to use `EVAL` instead.
Example:
- > set foo bar
- OK
- > eval "return redis.call('get','foo')" 0
- "bar"
- > evalsha 6b1bf486c81ceb7edf3c093f4c48582e38c0e791 0
- "bar"
- > evalsha ffffffffffffffffffffffffffffffffffffffff 0
- (error) `NOSCRIPT` No matching script. Please use `EVAL`.
+```
+> set foo bar
+OK
+> eval "return redis.call('get','foo')" 0
+"bar"
+> evalsha 6b1bf486c81ceb7edf3c093f4c48582e38c0e791 0
+"bar"
+> evalsha ffffffffffffffffffffffffffffffffffffffff 0
+(error) `NOSCRIPT` No matching script. Please use `EVAL`.
+```
The client library implementation can always optimistically send `EVALSHA` under
-the hoods even when the client actually called `EVAL`, in the hope the script
-was already seen by the server. If the `NOSCRIPT` error is returned `EVAL` will be used instead.
+the hood even when the client actually calls `EVAL`, in the hope the script was
+already seen by the server.
+If the `NOSCRIPT` error is returned `EVAL` will be used instead.
-Passing keys and arguments as `EVAL` additional arguments is also
-very useful in this context as the script string remains constant and can be
-efficiently cached by Redis.
+Passing keys and arguments as additional `EVAL` arguments is also very useful in
+this context as the script string remains constant and can be efficiently cached
+by Redis.
-Script cache semantics
----
+## Script cache semantics
Executed scripts are guaranteed to be in the script cache **forever**.
This means that if an `EVAL` is performed against a Redis instance all the
subsequent `EVALSHA` calls will succeed.
-The only way to flush the script cache is by explicitly calling the
-SCRIPT FLUSH command, that will *completely flush* the scripts cache removing
-all the scripts executed so far. This is usually
-needed only when the instance is going to be instantiated for another
-customer or application in a cloud environment.
-
-The reason why scripts can be cached for long time is that it is unlikely
-for a well written application to have so many different scripts to create
-memory problems. Every script is conceptually like the implementation of
-a new command, and even a large application will likely have just a few
-hundreds of that. Even if the application is modified many times and
-scripts will change, still the memory used is negligible.
-
-The fact that the user can count on Redis not removing scripts
-is semantically a very good thing. For instance an application taking
-a persistent connection to Redis can stay sure that if a script was
-sent once it is still in memory, thus for instance can use EVALSHA
-against those scripts in a pipeline without the chance that an error
-will be generated since the script is not known (we'll see this problem
-in its details later).
-
-The SCRIPT command
----
-
-Redis offers a SCRIPT command that can be used in order to control
-the scripting subsystem. SCRIPT currently accepts three different commands:
-
-* SCRIPT FLUSH. This command is the only way to force Redis to flush the
-scripts cache. It is mostly useful in a cloud environment where the same
-instance can be reassigned to a different user. It is also useful for
-testing client libraries implementations of the scripting feature.
-
-* SCRIPT EXISTS *sha1* *sha2* ... *shaN*. Given a list of SHA1 digests
-as arguments this command returns an array of 1 or 0, where 1 means the
-specific SHA1 is recognized as a script already present in the scripting
-cache, while 0 means that a script with this SHA1 was never seen before
-(or at least never seen after the latest SCRIPT FLUSH command).
-
-* SCRIPT LOAD *script*. This command registers the specified script in
-the Redis script cache. The command is useful in all the contexts where
-we want to make sure that `EVALSHA` will not fail (for instance during a
-pipeline or MULTI/EXEC operation), without the need to actually execute the
-script.
-
-* SCRIPT KILL. This command is the only wait to interrupt a long running
-script that reached the configured maximum execution time for scripts.
-The SCRIPT KILL command can only be used with scripts that did not modified
-the dataset during their execution (since stopping a read only script does
-not violate the scripting engine guaranteed atomicity).
-See the next sections for more information about long running scripts.
-
-Scripts as pure functions
----
+The only way to flush the script cache is by explicitly calling the SCRIPT
+FLUSH command, which will _completely flush_ the scripts cache removing all the
+scripts executed so far.
+This is usually needed only when the instance is going to be instantiated for
+another customer or application in a cloud environment.
+
+The reason why scripts can be cached for long time is that it is unlikely for
+a well written application to have enough different scripts to cause memory
+problems.
+Every script is conceptually like the implementation of a new command, and even
+a large application will likely have just a few hundred of them.
+Even if the application is modified many times and scripts will change, the
+memory used is negligible.
+
+The fact that the user can count on Redis not removing scripts is semantically a
+very good thing.
+For instance an application with a persistent connection to Redis can be sure
+that if a script was sent once it is still in memory, so EVALSHA can be used
+against those scripts in a pipeline without the chance of an error being
+generated due to an unknown script (we'll see this problem in detail later).
+
+## The SCRIPT command
+
+Redis offers a SCRIPT command that can be used in order to control the scripting
+subsystem.
+SCRIPT currently accepts three different commands:
+
+* SCRIPT FLUSH.
+ This command is the only way to force Redis to flush the scripts cache.
+ It is most useful in a cloud environment where the same instance can be
+ reassigned to a different user.
+ It is also useful for testing client libraries' implementations of the
+ scripting feature.
+
+* SCRIPT EXISTS _sha1_ _sha2_... _shaN_.
+ Given a list of SHA1 digests as arguments this command returns an array of
+ 1 or 0, where 1 means the specific SHA1 is recognized as a script already
+ present in the scripting cache, while 0 means that a script with this SHA1
+ was never seen before (or at least never seen after the latest SCRIPT FLUSH
+ command).
+
+* SCRIPT LOAD _script_.
+ This command registers the specified script in the Redis script cache.
+ The command is useful in all the contexts where we want to make sure that
+ `EVALSHA` will not fail (for instance during a pipeline or MULTI/EXEC
+ operation), without the need to actually execute the script.
+
+* SCRIPT KILL.
+ This command is the only way to interrupt a long-running script that reaches
+ the configured maximum execution time for scripts.
+ The SCRIPT KILL command can only be used with scripts that did not modify
+ the dataset during their execution (since stopping a read-only script does
+ not violate the scripting engine's guaranteed atomicity).
+ See the next sections for more information about long running scripts.
+
+## Scripts as pure functions
A very important part of scripting is writing scripts that are pure functions.
-Scripts executed in a Redis instance are replicated on slaves sending the
-same script, instead of the resulting commands. The same happens for the
-Append Only File. The reason is that scripts are much faster than sending
-commands one after the other to a Redis instance, so if the client is
-taking the master very busy sending scripts, turning this scripts into single
-commands for the slave / AOF would result in too much bandwidth for the
-replication link or the Append Only File (and also too much CPU since
-dispatching a command received via network is a lot more work for Redis
-compared to dispatching a command invoked by Lua scripts).
-
-The only drawback with this approach is that scripts are required to
-have the following property:
-
-* The script always evaluates the same Redis *write* commands with the
-same arguments given the same input data set. Operations performed by
-the script cannot depend on any hidden (non explicit) information or state
-that may change as script execution proceeds or between different executions of
-the script, nor can it depend on any external input from I/O devices.
+Scripts executed in a Redis instance are replicated on slaves by sending the
+script -- not the resulting commands.
+The same happens for the Append Only File.
+The reason is that sending a script to another Redis instance is much
+faster than sending the multiple commands the script generates, so if the
+client is sending many scripts to the master, converting the scripts into
+individual commands for the slave / AOF would result in too much bandwidth
+for the replication link or the Append Only File (and also too much CPU since
+dispatching a command received via network is a lot more work for Redis compared
+to dispatching a command invoked by Lua scripts).
+
+The only drawback with this approach is that scripts are required to have the
+following property:
+
+* The script always evaluates the same Redis _write_ commands with the same
+ arguments given the same input data set.
+ Operations performed by the script cannot depend on any hidden (non-explicit)
+ information or state that may change as script execution proceeds or between
+ different executions of the script, nor can it depend on any external input
+ from I/O devices.
Things like using the system time, calling Redis random commands like
`RANDOMKEY`, or using Lua random number generator, could result into scripts
-that will not evaluate always in the same way.
+that will not always evaluate in the same way.
In order to enforce this behavior in scripts Redis does the following:
-* Lua does not export commands to access the system time or other external state.
-
-* Redis will block the script with an error if a script will call a
-Redis command able to alter the data set **after** a Redis *random*
-command like `RANDOMKEY`, `SRANDMEMBER`, `TIME`. This means that if a script is
-read only and does not modify the data set it is free to call those commands.
-Note that a *random command* does not necessarily identifies a command that
-uses random numbers: any non deterministic command is considered a random
-command (the best example in this regard is the `TIME` command).
-
-* Redis commands that may return elements in random order, like `SMEMBERS`
-(because Redis Sets are *unordered*) have a different behavior when called from Lua, and undergone a silent lexicographical sorting filter before returning data to Lua scripts. So `redis.call("smembers",KEYS[1])` will always return the Set elements in the same order, while the same command invoked from normal clients may return different results even if the key contains exactly the same elements.
-
-* Lua pseudo random number generation functions `math.random` and
-`math.randomseed` are modified in order to always have the same seed every
-time a new script is executed. This means that calling `math.random` will
-always generate the same sequence of numbers every time a script is
-executed if `math.randomseed` is not used.
-
-However the user is still able to write commands with random behaviors
-using the following simple trick. Imagine I want to write a Redis
-script that will populate a list with N random integers.
-
-I can start writing the following script, using a small Ruby program:
-
- require 'rubygems'
- require 'redis'
-
- r = Redis.new
-
- RandomPushScript = <<EOF
- local i = tonumber(ARGV[1])
- local res
- while (i > 0) do
- res = redis.call('lpush',KEYS[1],math.random())
- i = i-1
- end
- return res
- EOF
-
- r.del(:mylist)
- puts r.eval(RandomPushScript,1,:mylist,10)
+* Lua does not export commands to access the system time or other external
+ state.
+
+* Redis will block the script with an error if a script calls a Redis
+ command able to alter the data set **after** a Redis _random_ command like
+ `RANDOMKEY`, `SRANDMEMBER`, `TIME`.
+ This means that if a script is read-only and does not modify the data set it
+ is free to call those commands.
+ Note that a _random command_ does not necessarily mean a command that uses
+ random numbers: any non-deterministic command is considered a random command
+ (the best example in this regard is the `TIME` command).
+
+* Redis commands that may return elements in random order, like `SMEMBERS`
+ (because Redis Sets are _unordered_) have a different behavior when called
+ from Lua, and undergo a silent lexicographical sorting filter before
+ returning data to Lua scripts.
+ So `redis.call("smembers",KEYS[1])` will always return the Set elements
+ in the same order, while the same command invoked from normal clients may
+ return different results even if the key contains exactly the same elements.
+
+* Lua pseudo random number generation functions `math.random` and
+ `math.randomseed` are modified in order to always have the same seed every
+ time a new script is executed.
+ This means that calling `math.random` will always generate the same sequence
+ of numbers every time a script is executed if `math.randomseed` is not used.
+
+However the user is still able to write commands with random behavior using the
+following simple trick.
+Imagine I want to write a Redis script that will populate a list with N random
+integers.
+
+I can start with this small Ruby program:
+
+```
+require 'rubygems'
+require 'redis'
+
+r = Redis.new
+
+RandomPushScript = <<EOF
+ local i = tonumber(ARGV[1])
+ local res
+ while (i > 0) do
+ res = redis.call('lpush',KEYS[1],math.random())
+ i = i-1
+ end
+ return res
+EOF
+
+r.del(:mylist)
+puts r.eval(RandomPushScript,1,:mylist,10)
+```
Every time this script executed the resulting list will have exactly the
following elements:
- > lrange mylist 0 -1
- 1) "0.74509509873814"
- 2) "0.87390407681181"
- 3) "0.36876626981831"
- 4) "0.6921941534114"
- 5) "0.7857992587545"
- 6) "0.57730350670279"
- 7) "0.87046522734243"
- 8) "0.09637165539729"
- 9) "0.74990198051087"
- 10) "0.17082803611217"
-
-In order to make it a pure function, but still making sure that every
-invocation of the script will result in different random elements, we can
-simply add an additional argument to the script, that will be used in order to
-seed the Lua pseudo random number generator. The new script will be like the
-following:
-
- RandomPushScript = <<EOF
- local i = tonumber(ARGV[1])
- local res
- math.randomseed(tonumber(ARGV[2]))
- while (i > 0) do
- res = redis.call('lpush',KEYS[1],math.random())
- i = i-1
- end
- return res
- EOF
-
- r.del(:mylist)
- puts r.eval(RandomPushScript,1,:mylist,10,rand(2**32))
-
-What we are doing here is sending the seed of the PRNG as one of the
-arguments. This way the script output will be the same given the same
-arguments, but we are changing one of the argument at every invocation,
-generating the random seed client side. The seed will be propagated as
-one of the arguments both in the replication link and in the Append Only
-File, guaranteeing that the same changes will be generated when the AOF
-is reloaded or when the slave will process the script.
+```
+> lrange mylist 0 -1
+ 1) "0.74509509873814"
+ 2) "0.87390407681181"
+ 3) "0.36876626981831"
+ 4) "0.6921941534114"
+ 5) "0.7857992587545"
+ 6) "0.57730350670279"
+ 7) "0.87046522734243"
+ 8) "0.09637165539729"
+ 9) "0.74990198051087"
+10) "0.17082803611217"
+```
+
+In order to make it a pure function, but still be sure that every invocation
+of the script will result in different random elements, we can simply add an
+additional argument to the script that will be used in order to seed the Lua
+pseudo-random number generator.
+The new script is as follows:
+
+```
+RandomPushScript = <<EOF
+ local i = tonumber(ARGV[1])
+ local res
+ math.randomseed(tonumber(ARGV[2]))
+ while (i > 0) do
+ res = redis.call('lpush',KEYS[1],math.random())
+ i = i-1
+ end
+ return res
+EOF
+
+r.del(:mylist)
+puts r.eval(RandomPushScript,1,:mylist,10,rand(2**32))
+```
+
+What we are doing here is sending the seed of the PRNG as one of the arguments.
+This way the script output will be the same given the same arguments, but we are
+changing one of the arguments in every invocation, generating the random seed
+client-side.
+The seed will be propagated as one of the arguments both in the replication
+link and in the Append Only File, guaranteeing that the same changes will be
+generated when the AOF is reloaded or when the slave processes the script.
Note: an important part of this behavior is that the PRNG that Redis implements
as `math.random` and `math.randomseed` is guaranteed to have the same output
-regardless of the architecture of the system running Redis. 32 or 64 bit systems
-like big or little endian systems will still produce the same output.
+regardless of the architecture of the system running Redis.
+32-bit, 64-bit, big-endian and little-endian systems will all produce the same
+output.
-Global variables protection
----
+## Global variables protection
Redis scripts are not allowed to create global variables, in order to avoid
-leaking data into the Lua state. If a script requires to take state across
-calls (a pretty uncommon need) it should use Redis keys instead.
+leaking data into the Lua state.
+If a script needs to maintain state between calls (a pretty uncommon need) it
+should use Redis keys instead.
-When a global variable access is attempted the script is terminated and EVAL returns with an error:
+When global variable access is attempted the script is terminated and EVAL
+returns with an error:
- redis 127.0.0.1:6379> eval 'a=10' 0
- (error) ERR Error running script (call to f_933044db579a2f8fd45d8065f04a8d0249383e57): user_script:1: Script attempted to create global variable 'a'
+```
+redis 127.0.0.1:6379> eval 'a=10' 0
+(error) ERR Error running script (call to f_933044db579a2f8fd45d8065f04a8d0249383e57): user_script:1: Script attempted to create global variable 'a'
+```
-Accessing a *non existing* global variable generates a similar error.
+Accessing a _non existing_ global variable generates a similar error.
-Using Lua debugging functionalities or other approaches like altering the meta
-table used to implement global protections, in order to circumvent globals
-protection, is not hard. However it is hardly possible to do it accidentally.
+Using Lua debugging functionality or other approaches like altering the meta
+table used to implement global protections in order to circumvent globals
+protection is not hard.
+However it is difficult to do it accidentally.
If the user messes with the Lua global state, the consistency of AOF and
replication is not guaranteed: don't do it.
-Note for Lua newbies: in order to avoid using global variables in your scripts simply declare every variable you are going to use using the *local* keyword.
+Note for Lua newbies: in order to avoid using global variables in your scripts
+simply declare every variable you are going to use using the _local_ keyword.
-Available libraries
----
+## Available libraries
The Redis Lua interpreter loads the following Lua libraries:
@@ -416,82 +456,98 @@ The Redis Lua interpreter loads the following Lua libraries:
* cjson lib.
* cmsgpack lib.
-Every Redis instance is *guaranteed* to have all the above libraries so you
-can be sure that the environment for your Redis scripts is always the same.
+Every Redis instance is _guaranteed_ to have all the above libraries so you can
+be sure that the environment for your Redis scripts is always the same.
-The CJSON library allows to manipulate JSON data in a very fast way from Lua.
+The CJSON library provides extremely fast JSON maniplation within Lua.
All the other libraries are standard Lua libraries.
-Emitting Redis logs from scripts
----
+## Emitting Redis logs from scripts
It is possible to write to the Redis log file from Lua scripts using the
`redis.log` function.
- redis.log(loglevel,message)
+```
+redis.log(loglevel,message)
+```
-loglevel is one of:
+`loglevel` is one of:
* `redis.LOG_DEBUG`
* `redis.LOG_VERBOSE`
* `redis.LOG_NOTICE`
* `redis.LOG_WARNING`
-They exactly correspond to the normal Redis log levels. Only logs emitted by scripting using a log level that is equal or greater than the currently configured
-Redis instance log level will be emitted.
+They correspond directly to the normal Redis log levels.
+Only logs emitted by scripting using a log level that is equal or greater than
+the currently configured Redis instance log level will be emitted.
-The `message` argument is simply a string. Example:
+The `message` argument is simply a string.
+Example:
- redis.log(redis.LOG_WARNING,"Something is wrong with this script.")
+```
+redis.log(redis.LOG_WARNING,"Something is wrong with this script.")
+```
Will generate the following:
- [32343] 22 Mar 15:21:39 # Something is wrong with this script.
+```
+[32343] 22 Mar 15:21:39 # Something is wrong with this script.
+```
-Sandbox and maximum execution time
----
+## Sandbox and maximum execution time
-Scripts should never try to access the external system, like the file system,
-nor calling any other system call. A script should just do its work operating
-on Redis data and passed arguments.
+Scripts should never try to access the external system, like the file system or
+any other system call.
+A script should only operate on Redis data and passed arguments.
Scripts are also subject to a maximum execution time (five seconds by default).
-This default timeout is huge since a script should run usually in a sub
-millisecond amount of time. The limit is mostly needed in order to avoid
-problems when developing scripts that may loop forever for a programming
-error.
-
-It is possible to modify the maximum time a script can be executed