Lua script series of redis

1. Redis has joined the lua virtual machine and can execute lua scripts. Provides solutions for complex redis operations. Performance is also good.

2. Lua execution is atomic.

3. It is a great thing for redis to join lua.

 

Previously used redis lua script. Just fix something simple. This time there are complexities to deal with. Encountered a lot of problems.

1, the definition of the method.

        This time the lua script requires multiple operations. Passing parameters requires a different action. Don't want to deal with if else if. Methods need to be defined. Defining methods in the usual way is problematic.

 

global variable protection

To prevent unnecessary data leakage into the Lua environment, Redis scripts do not allow the creation of global variables. If a script needs to maintain some state between executions, it should use a Redis key for state preservation.

Attempting to access a global variable in a script (whether the variable exists or not) will cause the script to stop and the EVAL command will return 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'

Lua's debug tools, or other facilities, such as printing (alter) the meta table used to implement global protection, can be used to implement global variable protection.

Implementing global variable protection is not difficult, but sometimes it happens accidentally. Once the user mixes the Lua global state in the script, AOF persistence and replication are not guaranteed, so please don't use global variables.

  

 

  The solution, redis has provided,

 

void scriptingEnableGlobalsProtection (lua_State * lua) {
    char *s[32];
    sds code = sdsempty();
    int j = 0;

    /* strict.lua from: http://metalua.luaforge.net/src/lib/strict.lua.html.
     * Modified to be adapted to Redis. */
    s[j++]="local dbg=debug\n";
    s[j++]="local mt = {}\n";
    s[j++]="setmetatable(_G, mt)\n";
    s[j++]="mt.__newindex = function (t, n, v)\n";
    s[j++]="  if dbg.getinfo(2) then\n";
    s[j++]="    local w = dbg.getinfo(2, \"S\").what\n";
    s[j++]="    if w ~= \"main\" and w ~= \"C\" then\n";
    s[j++]="      error(\"Script attempted to create global variable '\"..tostring(n)..\"'\", 2)\n";
    s[j++]="    end\n";
    s[j++]="  end\n";
    s[j++]="  rawset(t, n, v)\n";
    s[j++]="end\n";
    s[j++]="mt.__index = function (t, n)\n";
    s[j++]="  if dbg.getinfo(2) and dbg.getinfo(2, \"S\").what ~= \"C\" then\n";
    s[j++]="    error(\"Script attempted to access unexisting global variable '\"..tostring(n)..\"'\", 2)\n";
    s[j++]="  end\n";
    s[j++]="  return rawget(t, n)\n";
    s[j++]="end\n";
    s[j++]="debug = nil\n";
    s[j++]=NULL;

    for (j = 0; s[j] != NULL; j++) code = sdscatlen(code,s[j],strlen(s[j]));
    luaL_loadbuffer(lua,code,sdslen(code),"@enable_strict_lua");
    lua_pcall (lua, 0,0,0);
    sdsfree(code);
}

 Define a local variable of type table.

 

Then use setmeatable to version the local variables with _G.

You can bind local variables to methods.

 

 

2, return

      The return of the execute method is invalid. You need to execute return "data" at the end of the script to return the data. no return at the end of the script

 

3, the command attribute.

     Because the time command needs to be executed, the result is an error

Write commands not allowed after non deterministic commands. Call redis.replicate_commands() at the start of your script in order to switch to single commands replication mode

   After searching for a long time, it is important to find where the problem is. The commands of redis are divided into categories.

#define CMD_WRITE 1                   /* "w" flag */
#define CMD_READONLY 2                /* "r" flag */
#define CMD_DENYOOM 4                 /* "m" flag */
#define CMD_NOT_USED_1 8              /* no longer used flag */
#define CMD_ADMIN 16                  /* "a" flag */
#define CMD_PUBSUB 32                 /* "p" flag */
#define CMD_NOSCRIPT  64              /* "s" flag */
#define CMD_RANDOM 128                /* "R" flag */
#define CMD_SORT_FOR_SCRIPT 256       /* "S" flag */
#define CMD_LOADING 512               /* "l" flag */
#define CMD_STALE 1024                /* "t" flag */
#define CMD_SKIP_MONITOR 2048         /* "M" flag */
#define CMD_ASKING 4096               /* "k" flag */
#define CMD_FAST 8192                 /* "F" flag */

 

Please see the detailed classification, server.h or

http://blog.csdn.net/wtyvhreal/article/details/43193591

 

Commands of type REDIS_CMD_NOSCRIPT cannot be executed.

For REDIS_CMD_RANDOM type commands, the REDIS_CMD_WRITE command cannot be executed after the session is executed, which is also the reason for the consistent error. Finally the time command is removed and the client passes the timestamp.

 

4. KEYS, ARGV, are all table types and can be iterative.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326409306&siteId=291194637