Commands from the EVAL family evaluate Lua scripts using the Lua 5.1 interpreter running within the Tile38 server.
script is a text of a Lua 5.1 script. The content of the script will be used to create a Lua function on the server. That function will take no arguments and should return one Lua value. Note: the script should not start with the
numkeys is the number of tile38 keys that will be passed into EVAL.
Following that, the next
numkeys arguments are the tile38 keys that can be accessed by the script. The remaining tokens are the additional arguments that can be accessed by the script but do not represent the tile38 keys.
The keys and additional arguments are available from the script as global variables KEYS and ARGV, both are one-based arrays (Lua tables). Specifically, they keys will be available in the script as KEYS, KEYS, …, and the additional arguments will be available as ARGV, ARGV, …
The Lua environment inside the Tile38 server defines two functions to call other tile38 commands from a Lua script:
The only difference between these two functions is how they handle the errors that might happen when the tile38 command is called. The
tile38.call() will raise a Lua error, while
tile38.pcall() will return a Lua table containing the error message.
The arguments of
tile38.pcall() are the same tokens one would send as a tile38 command:
Note that the above call includes the key name into the script and sends 0 keys. This should be avoided in favor of the following form:
This is useful in many ways. One reason is the potential future features involving clustering/sharding of the data. Another immediate reason is that it is beneficial to have constant scripts into which different keys/args are sent. This allows caching the compiled script on the server and avoid compiling new Lua code each time the script is evaluated (see EVALSHA and SCRIPT LOAD for more details.)
The value returned by a Lua script will be converted from its Lua type to one of the types supported by RESP.
When a Lua script calls a tile38 command through
tile38.pcall(), the result of the call (a RESP value) is converted to Lua type. Similarly, when the script returns a value to the EVAL command, it is converted from a Lua type to RESP. The type conversion rules are as follows:
okkey and the status message as the value
errkey and the error message as the value
okkey -> RESP simple string
errkey -> RESP error
With these conversion rules, any RESP value that is converted to Lua and then back to RESP will be identical to the original.
There’s a couple of additional one-way Lua-RESP conversions:
The Lua environment inside the Tile38 server also defines these helper functions:
tile38.error_reply(error_string)returns an error reply, as if obtained by the failed
tile38.status_reply(status_string)returns a status reply, as if obtained by the successful
tile38.pcall()that returns a status reply.
tile38.sha1hex(input_string)returns a hex representation of a SHA1 digest.
tile38.distance_to(lat_a, lon_a, lat_b, lon_b)returns a distance between points
b, in meters.
DEADLINEis set inside the Lua environment. Its value is either
nil(no timeout) or a Unix epoch second of the deadline after which the script will be killed, if invoked with the TIMEOUT.
Tile38 provides three different levels of atomicity:
The reason for providing different atomicity levels is that in that the users might want to pick a particular behavior depending on their use case. Examples:
Tile38 has an internal caching mechanism that will avoid recompiling a script on every evaluation, so even if you send the same script multiple times it will only be compiled once.
SCRIPT LOAD"return tile38.pcall('set', KEYS, ARGV, 'point', ARGV, ARGV)" "d8bc159162250f39654a6466a92a66215814877b" EVALSHAd8bc159162250f39654a6466a92a66215814877b 1mykey myid2 33.1 -115.1 OK
The script caching is not persistent, meaning it will be lost when the tile38 server is restarted.
Commands relevant to script caching are:
The changes to the tile38 data made by scripts are replicated on the command level. In other words, when the script runs multiple commands, each command’s changes will be shipped to the replicas and replayed there.
The scripts are not allowed to create global variables, as this would leak memory in the re-used Lua state. An attempt to create a global variable will result in error:
Note: this measure can only prevent the accidental modifications of the global namespace. If the malicious user really wants to modify or delete existing global variables, there’s no protection we could put in place that the user could not undo. Therefore there’s no more protection for existing globals. Do not mess them up!
Any variables that the script needs to set up should be prepended with the
The following libraries are loaded in the Lua interpreter inside the Tile38 server:
Every Tile38 instance is guaranteed to have all these libraries so you can be sure that the environment for your scripts is always the same.
json is an external library, all the other libraries are standard Lua libraries, see Miscellaneous notes below.
The JSON library exposes
encode functions. Examples:
The following functions from standard Lua libraries are not available:
collectgarbagedoes not take any arguments and runs the garbage collector for the entire Tile38 server.
file:setvbufdoes not support a line buffering.
os.setenv(name, value)is a function that sets an environment variable.