gqinvs 发表于 2016-12-17 11:38:06

redis执行lua lua执行redis

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


[*]redis能执行lua脚本
[*]在lua脚本里能执行redis的命令
  接下来,我将通过一个简单的实例来解析redis如何完成上述两个工作的。

构建一个简单的redis

#define DICT_SIZE 100
struct redisDict {
char* key;
char* value;
intidx;
};
static void setCommand(const char *key, const char *value)
{
/* ignore memory issue for simple */
if (dict.idx + 1 <= DICT_SIZE) {
dict.key = (char *)malloc(strlen(key) + 1);
strcpy(dict.key, key);
dict.value = (char *)malloc(strlen(value) + 1);
strcpy(dict.value, value);
dict.idx += 1;
}
}
static const char *getCommand(const char *key)
{
int j;
for (j = 0; j <= dict.idx; j++) {
if (strcmp(dict.key, key) == 0) {
return dict.value;
}
}
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;


char* value;


intidx;


};

 

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 = (char *)malloc(strlen(key) + 1);


    strcpy(dict.key, key);


 

    dict.value = (char *)malloc(strlen(value) + 1);


    strcpy(dict.value, value);


 

    dict.idx += 1;


}


}

 

static const char *getCommand(const char *key)


{

int j;


for (j = 0; j <= dict.idx; j++) {


    if (strcmp(dict.key, key) == 0) {


      return dict.value;


    }


}


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]
查看完整版本: redis执行lua lua执行redis