Sunday, March 24, 2013

Scripting in Redis

Since Redis 2.6, it introduced scripting and is surprisingly easy.  It is using LUA 5.1 which I have never came across before but i can learn the basic syntax in an hour or so.

We are trying to create a cache that still has O(1) when retrieve entry with a certain id while maintaining the order of the entries.  Basically, we want a cache with feature of a hash and a list, so we decided to build a virtual cache where actually, it is implemented by a list cache an a hash cache.

when adding an entry to the cache, we'll have to add the id to the end of the list if it's not already in the list and put the (id,entry) pair to the hash.  In order to do that in an atomic fashion, we have to use script*.

the script look like this.

you can call any redis api using redis.call.  Notice the space after do, then and end, that's there because we're concatenating the strings without a space, it'll join with the next line's first command.

To call the script using RedisTemplate (with Jedis as connection factory), you'll have to get the native connection (Jedis) and use Jedis.eval to execute the script.

also, you can test your script using redis-cli directly.  Please note that the syntax is ./redis-cli --eval <script name> <number of key> <keys>... , <argv>...
e.g. ./redis-cli --eval test.lua 1 x , 1 2
 in the script, you can do
local key = KEYS[1]
local test1 = ARGV[1]
local test2 = ARGV[2]
and the comma has to have a space before and after it.  neither x, 1 2 nor x ,1 2 will work. 

* multi/exec can't do what we wanted to do because command inputs cannot depends on result from previous commands.