设为首页 收藏本站
查看: 1055|回复: 0

[经验分享] redis执行lua lua执行redis

[复制链接]

尚未签到

发表于 2016-12-17 11:38:06 | 显示全部楼层 |阅读模式
  redis-2.6支持通过EVAL命令来执行lua脚本,对lua脚本的支持扩展了redis的应用场景,redis支持路脚本需要做2件事


  • redis能执行lua脚本
  • 在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");
}

完整示例代码



1
2

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


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











  来自CODE的代码片

script.lua




   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116

/* gcc -o test_lua lua.c -llua -lm -ldl */

#include <lua.h>

#include <lauxlib.h>

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

#include <assert.h>

 

#define DICT_SIZE 100

struct redisDict {


  char* key[DICT_SIZE];


  char* value[DICT_SIZE];


  int  idx;


};

 

struct redisDict dict;


lua_State *L;


 

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";


}

 

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 scriptingRun(const char* filename)


{

  int status = luaL_loadfile(L, filename);


  if (status) {


    fprintf(stderr, "Couldn't load file: %s\n", lua_tostring(L, -1));


    exit(1);


  }


 

  /* Ask Lua to run our little script */


  int result = lua_pcall(L, 0, LUA_MULTRET, 0);


  if (result) {


    fprintf(stderr, "Failed to run script: %s\n", lua_tostring(L, -1));


    exit(1);


  }


 

  /* Get the returned value at the top of the stack (index -1) */


  const char *value = lua_tostring(L, -1);


 

  printf("%s\n", value);


 

  lua_pop(L, 1);  /* Take the returned value out of the stack */


  lua_close(L);   /* Cya, Lua */


}

 

static void scriptingInit()


{

  /*


   * All Lua contexts are held in this structure. We work with it almost

   * all the time.

   */

  L = luaL_newstate();


 

  /* Load Lua libraries */


  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");


}

 

int main(void)


{

  scriptingInit();


  scriptingRun("script.lua");


  return 0;


}




运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-315561-1-1.html 上篇帖子: Redis作者谈Redis应用场景 下篇帖子: memcached与redis比较
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表