summaryrefslogtreecommitdiffstats
path: root/iredis/data/commands/eval.md
diff options
context:
space:
mode:
Diffstat (limited to 'iredis/data/commands/eval.md')
-rw-r--r--iredis/data/commands/eval.md919
1 files changed, 15 insertions, 904 deletions
diff --git a/iredis/data/commands/eval.md b/iredis/data/commands/eval.md
index f85d727..079edeb 100644
--- a/iredis/data/commands/eval.md
+++ b/iredis/data/commands/eval.md
@@ -1,913 +1,24 @@
-## Introduction to EVAL
+Invoke the execution of a server-side Lua script.
-`EVAL` and `EVALSHA` are used to evaluate scripts using the Lua interpreter
-built into Redis starting from version 2.6.0.
+The first argument is the script's source code.
+Scripts are written in [Lua](https://lua.org) and executed by the embedded [Lua 5.1](/topics/lua-api) interpreter in Redis.
-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 is the number of input key name arguments, followed by all the keys accessed by the script.
+These names of input keys are available to the script as the [_KEYS_ global runtime variable](/topics/lua-api#the-keys-global-variable)
+Any additional input arguments **should not** represent names of keys.
-The second argument of `EVAL` is the number of arguments that follows the script
-(starting from the third argument) that represent Redis key names. The arguments
-can be accessed by Lua using the `!KEYS` global variable in the form of a
-one-based array (so `KEYS[1]`, `KEYS[2]`, ...).
+**Important:**
+to ensure the correct execution of scripts, both in standalone and clustered deployments, all names of keys that a script accesses must be explicitly provided as input key arguments.
+The script **should only** access keys whose names are given as input arguments.
+Scripts **should never** access keys with programmatically-generated names or based on the contents of data structures stored in the database.
-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]`, ...).
+Please refer to the [Redis Programmability](/topics/programmability) and [Introduction to Eval Scripts](/topics/eval-intro) for more information about Lua scripts.
-The following example should clarify what stated above:
+@examples
-```
-> 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.
-
-It is possible to call Redis commands from a Lua script using two different Lua
-functions:
-
-- `redis.call()`
-- `redis.pcall()`
-
-`redis.call()` is similar to `redis.pcall()`, the only difference is that if a
-Redis command call will result in an error, `redis.call()` will raise a Lua
-error that in turn will force `EVAL` to return an error to the command caller,
-while `redis.pcall` will trap the error and return a Lua table representing the
-error.
-
-The arguments of the `redis.call()` and `redis.pcall()` functions are all the
-arguments of a well formed Redis command:
-
-```
-> eval "return redis.call('set','foo','bar')" 0
-OK
-```
-
-The above script 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:
-
-```
-> eval "return redis.call('set',KEYS[1],'bar')" 1 foo
-OK
-```
-
-All Redis commands must be analyzed before execution to determine which keys the
-command will operate on. In order for this to be true for `EVAL`, keys must be
-passed explicitly. This is useful in many ways, but especially to make sure
-Redis Cluster can forward your request to the appropriate cluster node.
-
-Note 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.
-
-## 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 the Redis protocol when calling a Redis command and 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 the initial value.
-
-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.
-
-- Redis integer reply -> Lua number
-- Redis bulk reply -> Lua string
-- Redis multi bulk reply -> Lua table (may have other Redis data types nested)
-- Redis status reply -> Lua table with a single `ok` field containing the status
-- Redis error reply -> Lua table with a single `err` field containing the error
-- Redis Nil bulk reply and Nil multi bulk reply -> Lua false boolean type
-
-**Lua to Redis** conversion table.
-
-- Lua number -> Redis integer reply (the number is converted into an integer)
-- Lua string -> Redis bulk reply
-- Lua table (array) -> Redis multi bulk reply (truncated to the first nil inside
- the Lua array if any)
-- Lua table with a single `ok` field -> Redis status reply
-- 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
-Redis to Lua conversion rule:
-
-- Lua boolean true -> Redis integer reply with value of 1.
-
-Lastly, there are three important rules to note:
-
-- Lua has a single numerical type, Lua numbers. There is no distinction between
- integers and floats. So we always convert Lua numbers into integer replies,
- removing the decimal part of the number if any. **If you want to return a
- float from Lua you should return it as a string**, exactly like Redis itself
- does (see for instance the `ZSCORE` command).
-- There is
- [no simple way to have nils inside Lua arrays](http://www.lua.org/pil/19.1.html),
- this is a result of Lua table semantics, so when Redis converts a Lua array
- into Redis protocol the conversion is stopped if a nil is encountered.
-- When a Lua table contains keys (and their values), the converted Redis reply
- will **not** include them.
-
-**RESP3 mode conversion rules**: note that the Lua engine can work in RESP3 mode
-using the new Redis 6 protocol. In this case there are additional conversion
-rules, and certain conversions are also modified compared to the RESP2 mode.
-Please refer to the RESP3 section of this document for more information.
+The following example will run a script that returns the first argument that it gets.
-Here are a few conversion examples:
-
-```
-> 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 redis.call('get','foo')" 0
-"bar"
-```
-
-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.
-
-In the following example we can see how floats and arrays containing nils and
-keys are handled:
-
-```
-> eval "return {1,2,3.3333,somekey='somevalue','foo',nil,'bar'}" 0
-1) (integer) 1
-2) (integer) 2
-3) (integer) 3
-4) "foo"
-```
-
-As you can see 3.333 is converted into 3, _somekey_ is excluded, and the _bar_
-string is never returned as there is a nil before.
-
-## Helper functions to return Redis types
-
-There are two helper functions to return Redis types from Lua.
-
-- `redis.error_reply(error_string)` returns an error reply. This function simply
- returns a single field table with the `err` field set to the specified string
- for you.
-- `redis.status_reply(status_string)` returns a status reply. This function
- simply returns a single field table with the `ok` field set to the specified
- string for you.
-
-There is no difference between using the helper functions or directly returning
-the table with the specified format, so the following two forms are equivalent:
-
- return {err="My Error"}
- return redis.error_reply("My Error")
-
-## 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. This semantic is
-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.
-
-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.
-
-## Error handling
-
-As already stated, calls to `redis.call()` resulting in a Redis command error
-will stop the execution of the script and return an 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
```
-
-Using `redis.pcall()` 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()`.
-
-## Running Lua under low memory conditions
-
-When the memory usage in Redis exceeds the `maxmemory` limit, the first write
-command encountered in the Lua script that uses additional memory will cause the
-script to abort (unless `redis.pcall` was used). However, one thing to caution
-here is that if the first write command does not use additional memory such as
-DEL, LREM, or SREM, etc, Redis will allow it to run and all subsequent commands
-in the Lua script will execute to completion for atomicity. If the subsequent
-writes in the script generate additional memory, the Redis memory usage can go
-over `maxmemory`.
-
-Another possible way for Lua script to cause Redis memory usage to go above
-`maxmemory` happens when the script execution starts when Redis is slightly
-below `maxmemory` so the first write command in the script is allowed. As the
-script executes, subsequent write commands continue to generate memory and
-causes the Redis server to go above `maxmemory`.
-
-In those scenarios, it is recommended to configure the `maxmemory-policy` not to
-use `noeviction`. Also Lua scripts should be short so that evictions of items
-can happen in between Lua scripts.
-
-## 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.
-
-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 implementations of a command.
-
-- Deployment is hard if we have to make sure all instances contain a given
- command, especially in a distributed environment.
-
-- Reading application code, the complete semantics might not be clear since the
- application calls commands defined server side.
-
-In order to avoid these problems while avoiding the bandwidth penalty, Redis
-implements the `EVALSHA` command.
-
-`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 with a matching SHA1 digest, the script
- is executed.
-
-- 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`.
-```
-
-The client library implementation can always optimistically send `EVALSHA` under
-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 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
-
-Executed scripts are guaranteed to be in the script cache of a given execution
-of a Redis instance forever. This means that if an `EVAL` is performed against a
-Redis instance all the subsequent `EVALSHA` calls will succeed.
-
-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 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.
-
-Also, as already mentioned, restarting a Redis instance flushes the script
-cache, which is not persistent. However from the point of view of the client
-there are only two ways to make sure a Redis instance was not restarted between
-two different commands.
-
-- The connection we have with the server is persistent and was never closed so
- far.
-- The client explicitly checks the `runid` field in the `INFO` command in order
- to make sure the server was not restarted and is still the same process.
-
-Practically speaking, for the client it is much better to simply assume that in
-the context of a given connection, cached scripts are guaranteed to be there
-unless an administrator explicitly called the `SCRIPT FLUSH` command.
-
-The fact that the user can count on Redis not removing scripts is semantically
-useful in the context of pipelining.
-
-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).
-
-A common pattern is to call `SCRIPT LOAD` to load all the scripts that will
-appear in a pipeline, then use `EVALSHA` directly inside the pipeline without
-any need to check for errors resulting from the script hash not being
-recognized.
-
-## 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
-
-_Note: starting with Redis 5, scripts are always replicated as effects and not
-sending the script verbatim. So the following section is mostly applicable to
-Redis version 4 or older._
-
-A very important part of scripting is writing scripts that are pure functions.
-Scripts executed in a Redis instance are, by default, propagated to replicas and
-to the AOF file by sending the script itself -- not the resulting commands.
-
-The reason is that sending a script to another Redis instance is often 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 replica / 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).
-
-Normally replicating scripts instead of the effects of the scripts makes sense,
-however not in all the cases. So starting with Redis 3.2, the scripting engine
-is able to, alternatively, replicate the sequence of write commands resulting
-from the script execution, instead of replication the script itself. See the
-next section for more information. In this section we'll assume that scripts are
-replicated by sending the whole script. Let's call this replication mode **whole
-scripts replication**.
-
-The main drawback with the _whole scripts replication_ approach is that scripts
-are required to have the following property:
-
-- The script must 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 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 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).
-- In Redis version 4, 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. However starting with Redis 5 there is no longer such
- ordering step, because Redis 5 replicates scripts in a way that no longer
- needs non-deterministic commands to be converted into deterministic ones. In
- general, even when developing for Redis 4, never assume that certain commands
- in Lua will be ordered, but instead rely on the documentation of the original
- command you call to see the properties it provides.
-- 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,[:mylist],[10,rand(2**32)])
-```
-
-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 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:
-
+> EVAL "return ARGV[1]" 0 hello
+"hello"
```
-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 replica 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-bit, 64-bit,
-big-endian and little-endian systems will all produce the same output.
-
-## Replicating commands instead of scripts
-
-_Note: starting with Redis 5, the replication method described in this section
-(scripts effects replication) is the default and does not need to be explicitly
-enabled._
-
-Starting with Redis 3.2, it is possible to select an alternative replication
-method. Instead of replication whole scripts, we can just replicate single write
-commands generated by the script. We call this **script effects replication**.
-
-In this replication mode, while Lua scripts are executed, Redis collects all the
-commands executed by the Lua scripting engine that actually modify the dataset.
-When the script execution finishes, the sequence of commands that the script
-generated are wrapped into a MULTI / EXEC transaction and are sent to replicas
-and AOF.
-
-This is useful in several ways depending on the use case:
-
-- When the script is slow to compute, but the effects can be summarized by a few
- write commands, it is a shame to re-compute the script on the replicas or when
- reloading the AOF. In this case to replicate just the effect of the script is
- much better.
-- When script effects replication is enabled, the controls about non
- deterministic functions are disabled. You can, for example, use the `TIME` or
- `SRANDMEMBER` commands inside your scripts freely at any place.
-- The Lua PRNG in this mode is seeded randomly at every call.
-
-In order to enable script effects replication, you need to issue the following
-Lua command before any write operated by the script:
-
- redis.replicate_commands()
-
-The function returns true if the script effects replication was enabled,
-otherwise if the function was called after the script already called some write
-command, it returns false, and normal whole script replication is used.
-
-## Selective replication of commands
-
-When script effects replication is selected (see the previous section), it is
-possible to have more control in the way commands are replicated to replicas and
-AOF. This is a very advanced feature since **a misuse can do damage** by
-breaking the contract that the master, replicas, and AOF, all must contain the
-same logical content.
-
-However this is a useful feature since, sometimes, we need to execute certain
-commands only in the master in order to create, for example, intermediate
-values.
-
-Think at a Lua script where we perform an intersection between two sets. Pick
-five random elements, and create a new set with this five random elements.
-Finally we delete the temporary key representing the intersection between the
-two original sets. What we want to replicate is only the creation of the new set
-with the five elements. It's not useful to also replicate the commands creating
-the temporary key.
-
-For this reason, Redis 3.2 introduces a new command that only works when script
-effects replication is enabled, and is able to control the scripting replication
-engine. The command is called `redis.set_repl()` and fails raising an error if
-called when script effects replication is disabled.
-
-The command can be called with four different arguments:
-
- redis.set_repl(redis.REPL_ALL) -- Replicate to AOF and replicas.
- redis.set_repl(redis.REPL_AOF) -- Replicate only to AOF.
- redis.set_repl(redis.REPL_REPLICA) -- Replicate only to replicas (Redis >= 5)
- redis.set_repl(redis.REPL_SLAVE) -- Used for backward compatibility, the same as REPL_REPLICA.
- redis.set_repl(redis.REPL_NONE) -- Don't replicate at all.
-
-By default the scripting engine is always set to `REPL_ALL`. By calling this
-function the user can switch on/off AOF and or replicas propagation, and turn
-them back later at her/his wish.
-
-A simple example follows:
-
- redis.replicate_commands() -- Enable effects replication.
- redis.call('set','A','1')
- redis.set_repl(redis.REPL_NONE)
- redis.call('set','B','2')
- redis.set_repl(redis.REPL_ALL)
- redis.call('set','C','3')
-
-After running the above script, the result is that only keys A and C will be
-created on replicas and AOF.
-
-## 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 needs to maintain state between
-calls (a pretty uncommon need) it should use Redis keys instead.
-
-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'
-```
-
-Accessing a _non existing_ global variable generates a similar error.
-
-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.
-
-## Using SELECT inside scripts
-
-It is possible to call `SELECT` inside Lua scripts like with normal clients,
-However one subtle aspect of the behavior changes between Redis 2.8.11 and Redis
-2.8.12. Before the 2.8.12 release the database selected by the Lua script was
-_transferred_ to the calling script as current database. Starting from Redis
-2.8.12 the database selected by the Lua script only affects the execution of the
-script itself, but does not modify the database selected by the client calling
-the script.
-
-The semantic change between patch level releases was needed since the old
-behavior was inherently incompatible with the Redis replication layer and was
-the cause of bugs.
-
-## Using Lua scripting in RESP3 mode
-
-Starting with Redis version 6, the server supports two different protocols. One
-is called RESP2, and is the old protocol: all the new connections to the server
-start in this mode. However clients are able to negotiate the new protocol using
-the `HELLO` command: this way the connection is put in RESP3 mode. In this mode
-certain commands, like for instance `HGETALL`, reply with a new data type (the
-Map data type in this specific case). The RESP3 protocol is semantically more
-powerful, however most scripts are OK with using just RESP2.
-
-The Lua engine always assumes to run in RESP2 mode when talking with Redis, so
-whatever the connection that is invoking the `EVAL` or `EVALSHA` command is in
-RESP2 or RESP3 mode, Lua scripts will, by default, still see the same kind of
-replies they used to see in the past from Redis, when calling commands using the
-`redis.call()` built-in function.
-
-However Lua scripts running in Redis 6 or greater, are able to switch to RESP3
-mode, and get the replies using the new available types. Similarly Lua scripts
-are able to reply to clients using the new types. Please make sure to understand
-[the capabilities for RESP3](https://github.com/antirez/resp3) before continuing
-reading this section.
-
-In order to switch to RESP3 a script should call this function:
-
- redis.setresp(3)
-
-Note that a script can switch back and forth from RESP3 and RESP2 by calling the
-function with the argument '3' or '2'.
-
-At this point the new conversions are available, specifically:
-
-**Redis to Lua** conversion table specific to RESP3:
-
-- Redis map reply -> Lua table with a single `map` field containing a Lua table
- representing the fields and values of the map.
-- Redis set reply -> Lua table with a single `set` field containing a Lua table
- representing the elements of the set as fields, having as value just `true`.
-- Redis new RESP3 single null value -> Lua nil.
-- Redis true reply -> Lua true boolean value.
-- Redis false reply -> Lua false boolean value.
-- Redis double reply -> Lua table with a single `score` field containing a Lua
- number representing the double value.
-- All the RESP2 old conversions still apply.
-
-**Lua to Redis** conversion table specific for RESP3.
-
-- Lua boolean -> Redis boolean true or false. **Note that this is a change
- compared to the RESP2 mode**, where returning true from Lua returned the
- number 1 to the Redis client, and returning false used to return NULL.
-- Lua table with a single `map` field set to a field-value Lua table -> Redis
- map reply.
-- Lua table with a single `set` field set to a field-value Lua table -> Redis
- set reply, the values are discarded and can be anything.
-- Lua table with a single `double` field set to a field-value Lua table -> Redis
- double reply.
-- Lua null -> Redis RESP3 new null reply (protocol `"_\r\n"`).
-- All the RESP2 old conversions still apply unless specified above.
-
-There is one key thing to understand: in case Lua replies with RESP3 types, but
-the connection calling Lua is in RESP2 mode, Redis will automatically convert
-the RESP3 protocol to RESP2 compatible protocol, as it happens for normal
-commands. For instance returning a map type to a connection in RESP2 mode will
-have the effect of returning a flat array of fields and values.
-
-## Available libraries
-
-The Redis Lua interpreter loads the following Lua libraries:
-
-- `base` lib.
-- `table` lib.
-- `string` lib.
-- `math` lib.
-- `struct` lib.
-- `cjson` lib.
-- `cmsgpack` lib.
-- `bitop` lib.
-- `redis.sha1hex` function.
-- `redis.breakpoint and redis.debug` function in the context of the
- [Redis Lua debugger](/topics/ldb).
-
-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.
-
-struct, CJSON and cmsgpack are external libraries, all the other libraries are
-standard Lua libraries.
-
-### struct
-
-struct is a library for packing/unpacking structures within Lua.
-
-```
-Valid formats:
-> - big endian
-< - little endian
-![num] - alignment
-x - padding
-b/B - signed/unsigned byte
-h/H - signed/unsigned short
-l/L - signed/unsigned long
-T - size_t
-i/In - signed/unsigned integer with size `n' (default is size of int)
-cn - sequence of `n' chars (from/to a string); when packing, n==0 means
- the whole string; when unpacking, n==0 means use the previous
- read number as the string length
-s - zero-terminated string
-f - float
-d - double
-' ' - ignored
-```
-
-Example:
-
-```
-127.0.0.1:6379> eval 'return struct.pack("HH", 1, 2)' 0
-"\x01\x00\x02\x00"
-127.0.0.1:6379> eval 'return {struct.unpack("HH", ARGV[1])}' 0 "\x01\x00\x02\x00"
-1) (integer) 1
-2) (integer) 2
-3) (integer) 5
-127.0.0.1:6379> eval 'return struct.size("HH")' 0
-(integer) 4
-```
-
-### CJSON
-
-The CJSON library provides extremely fast JSON manipulation within Lua.
-
-Example:
-
-```
-redis 127.0.0.1:6379> eval 'return cjson.encode({["foo"]= "bar"})' 0
-"{\"foo\":\"bar\"}"
-redis 127.0.0.1:6379> eval 'return cjson.decode(ARGV[1])["foo"]' 0 "{\"foo\":\"bar\"}"
-"bar"
-```
-
-### cmsgpack
-
-The cmsgpack library provides simple and fast MessagePack manipulation within
-Lua.
-
-Example:
-
-```
-127.0.0.1:6379> eval 'return cmsgpack.pack({"foo", "bar", "baz"})' 0
-"\x93\xa3foo\xa3bar\xa3baz"
-127.0.0.1:6379> eval 'return cmsgpack.unpack(ARGV[1])' 0 "\x93\xa3foo\xa3bar\xa3baz"
-1) "foo"
-2) "bar"
-3) "baz"
-```
-
-### bitop
-
-The Lua Bit Operations Module adds bitwise operations on numbers. It is
-available for scripting in Redis since version 2.8.18.
-
-Example:
-
-```
-127.0.0.1:6379> eval 'return bit.tobit(1)' 0
-(integer) 1
-127.0.0.1:6379> eval 'return bit.bor(1,2,4,8,16,32,64,128)' 0
-(integer) 255
-127.0.0.1:6379> eval 'return bit.tohex(422342)' 0
-"000671c6"
-```
-
-It supports several other functions: `bit.tobit`, `bit.tohex`, `bit.bnot`,
-`bit.band`, `bit.bor`, `bit.bxor`, `bit.lshift`, `bit.rshift`, `bit.arshift`,
-`bit.rol`, `bit.ror`, `bit.bswap`. All available functions are documented in the
-[Lua BitOp documentation](http://bitop.luajit.org/api.html)
-
-### `redis.sha1hex`
-
-Perform the SHA1 of the input string.
-
-Example:
-
-```
-127.0.0.1:6379> eval 'return redis.sha1hex(ARGV[1])' 0 "foo"
-"0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"
-```
-
-## 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)
-```
-
-`loglevel` is one of:
-
-- `redis.LOG_DEBUG`
-- `redis.LOG_VERBOSE`
-- `redis.LOG_NOTICE`
-- `redis.LOG_WARNING`
-
-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:
-
-```
-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.
-```
-
-## Sandbox and maximum execution time
-
-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 usually run in under a
-millisecond. The limit is mostly to handle accidental infinite loops created
-during development.
-
-It is possible to modify the maximum time a script can be executed with
-millisecond precision, either via `redis.conf` or using the CONFIG GET / CONFIG
-SET command. The configuration parameter affecting max execution time is called
-`lua-time-limit`.
-
-When a script reaches the timeout it is not automatically terminated by Redis
-since this violates the contract Redis has with the scripting engine to ensure
-that scripts are atomic. Interrupting a script means potentially leaving the
-dataset with half-written data. For this reasons when a script executes for more
-than the specified time the following happens:
-
-- Redis logs that a script is running too long.
-- It starts accepting commands again from other clients, but will reply with a
- BUSY error to all the clients sending normal commands. The only allowed
- commands in this status are `SCRIPT KILL` and `SHUTDOWN NOSAVE`.
-- It is possible to terminate a script that executes only read-only commands
- using the `SCRIPT KILL` command. This does not violate the scripting semantic
- as no data was yet written to the dataset by the script.
-- If the script already called write commands the only allowed command becomes
- `SHUTDOWN NOSAVE` that stops the server without saving the current data set on
- disk (basically the server is aborted).
-
-## EVALSHA in the context of pipelining
-
-Care should be taken when executing `EVALSHA` in the context of a pipelined
-request, since even in a pipeline the order of execution of commands must be
-guaranteed. If `EVALSHA` will return a `NOSCRIPT` error the command can not be
-reissued later otherwise the order of execution is violated.
-
-The client library implementation should take one of the following approaches:
-
-- Always use plain `EVAL` when in the context of a pipeline.
-
-- Accumulate all the commands to send into the pipeline, then check for `EVAL`
- commands and use the `SCRIPT EXISTS` command to check if all the scripts are
- already defined. If not, add `SCRIPT LOAD` commands on top of the pipeline as
- required, and use `EVALSHA` for all the `EVAL` calls.
-
-## Debugging Lua scripts
-
-Starting with Redis 3.2, Redis has support for native Lua debugging. The Redis
-Lua debugger is a remote debugger consisting of a server, which is Redis itself,
-and a client, which is by default `redis-cli`.
-
-The Lua debugger is described in the [Lua scripts debugging](/topics/ldb)
-section of the Redis documentation.