IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    redis lua原理分析

    ydzhang发表于 2015-02-01 12:44:06
    love 0

    redis-2.6支持通过EVAL命令来执行lua脚本,对lua脚本的支持扩展了redis的应用场景,redis支持路脚本需要做2件事

    1. redis能执行lua脚本
    2. 在lua脚本里能执行redis的命令

    接下来,我将通过一个简单的实例来解析redis如何完成上述两个工作的。

    构建一个简单的redis

    #define DICT_SIZE 100
    struct redisDict {
      char* key[DICT_SIZE];
      char* value[DICT_SIZE];
      int  idx;
    };
    
    static void setCommand(const char *key, const char *value)
    {
        /* ignore memory issue for simple */
        if (dict.idx + 1 <= DICT_SIZE) {
        dict.key[dict.idx] = (char *)malloc(strlen(key) + 1);
        strcpy(dict.key[dict.idx], key);
    
        dict.value[dict.idx] = (char *)malloc(strlen(value) + 1);
        strcpy(dict.value[dict.idx], value);
    
        dict.idx += 1;
      }
    }
    
    static const char *getCommand(const char *key)
    {
      int j;
      for (j = 0; j <= dict.idx; j++) {
        if (strcmp(dict.key[j], key) == 0) {
          return dict.value[j];
        }
      }
      return "KeyNotFound";
    }
    

    上述代码实现了一个伪redis,支持setCommand、getCommand。

    C调用lua脚本

    具体例子参考http://lua-users.org/wiki/SimpleLuaApiExample

    /*
     * All Lua contexts are held in this structure. We work with it almost
     * all the time.
     */
    lua_State *L = luaL_newstate();
    
    luaL_openlibs(L); /* Load Lua libraries */
    
    /* Load the file containing the script we are going to run */
    status = luaL_loadfile(L, "script.lua");
    
    /* Ask Lua to run our little script */
    result = lua_pcall(L, 0, LUA_MULTRET, 0);
    

    上述代码片段中,其中script.lua是一个lua脚本。redis里稍有不同,redis里的脚本是通过EVAL命令传递到服务器端,redis将脚本拼成一个lua函数,然后调用loadbuffer,而这里从文件执行脚本调用的loadfile。

    lua调用C函数

    下面的lua代码里,调用的是redis的setCommand和getCommand。

    redis.call("set", "foo", "bar");

    return redis.call("get", "foo");

    要想lua脚本能调用C代码,需要现在lua环境注册对应的C函数,参考redis的scriptingInit函数。

    static int call(lua_State *L)
    {
      int argc = lua_gettop(L);
      const char *cmd = lua_tostring(L, 1);
      const char *key = lua_tostring(L, 2);
      if (strcmp(cmd, "set") == 0) {
        assert(argc == 3);
        const char *value = lua_tostring(L, 3);
        setCommand(key, value);
       return 0;
      } else if (strcmp(cmd, "get") == 0) {
        assert(argc == 2);
        lua_pushstring(L, getCommand(key));
        return 1;
      }
    
      lua_pushstring(L, "Invalid Command");
      return 1;
    }
    
    static void scriptingInit()
    {
    
      L = luaL_newstate();
    
      luaL_openlibs(L);
    
      /* Register the redis commands table and fields */
      lua_newtable(L);
    
      /* redis.call */
      lua_pushstring(L, "call");
      lua_pushcfunction(L, call);
      lua_settable(L, -3);
    
      /* Finally set the table as 'redis' global var. */
      lua_setglobal(L, "redis");
    }
    

    完整示例代码


    The post redis lua原理分析 appeared first on Yun Notes.



沪ICP备19023445号-2号
友情链接