]> git.saurik.com Git - redis.git/blame - src/scripting.c
Scripting: Reset Lua fake client reply_bytes after command execution.
[redis.git] / src / scripting.c
CommitLineData
7585836e 1#include "redis.h"
2#include "sha1.h"
e108bab0 3#include "rand.h"
7585836e 4
5#include <lua.h>
6#include <lauxlib.h>
7#include <lualib.h>
7229d60d 8#include <ctype.h>
e108bab0 9#include <math.h>
7585836e 10
532e0f5d 11char *redisProtocolToLuaType_Int(lua_State *lua, char *reply);
12char *redisProtocolToLuaType_Bulk(lua_State *lua, char *reply);
13char *redisProtocolToLuaType_Status(lua_State *lua, char *reply);
3791000f 14char *redisProtocolToLuaType_Error(lua_State *lua, char *reply);
15char *redisProtocolToLuaType_MultiBulk(lua_State *lua, char *reply);
e108bab0 16int redis_math_random (lua_State *L);
17int redis_math_randomseed (lua_State *L);
2f2e6ad4 18void sha1hex(char *digest, char *script, size_t len);
532e0f5d 19
20/* Take a Redis reply in the Redis protocol format and convert it into a
21 * Lua type. Thanks to this function, and the introduction of not connected
22 * clients, it is trvial to implement the redis() lua function.
23 *
24 * Basically we take the arguments, execute the Redis command in the context
25 * of a non connected client, then take the generated reply and convert it
26 * into a suitable Lua type. With this trick the scripting feature does not
27 * need the introduction of a full Redis internals API. Basically the script
28 * is like a normal client that bypasses all the slow I/O paths.
29 *
30 * Note: in this function we do not do any sanity check as the reply is
548efd91 31 * generated by Redis directly. This allows us to go faster.
532e0f5d 32 * The reply string can be altered during the parsing as it is discared
33 * after the conversion is completed.
34 *
35 * Errors are returned as a table with a single 'err' field set to the
36 * error string.
37 */
38
39char *redisProtocolToLuaType(lua_State *lua, char* reply) {
40 char *p = reply;
41
42 switch(*p) {
43 case ':':
44 p = redisProtocolToLuaType_Int(lua,reply);
45 break;
46 case '$':
47 p = redisProtocolToLuaType_Bulk(lua,reply);
48 break;
49 case '+':
50 p = redisProtocolToLuaType_Status(lua,reply);
51 break;
3791000f 52 case '-':
53 p = redisProtocolToLuaType_Error(lua,reply);
54 break;
55 case '*':
56 p = redisProtocolToLuaType_MultiBulk(lua,reply);
57 break;
532e0f5d 58 }
59 return p;
60}
61
62char *redisProtocolToLuaType_Int(lua_State *lua, char *reply) {
63 char *p = strchr(reply+1,'\r');
64 long long value;
65
66 string2ll(reply+1,p-reply-1,&value);
67 lua_pushnumber(lua,(lua_Number)value);
68 return p+2;
69}
70
71char *redisProtocolToLuaType_Bulk(lua_State *lua, char *reply) {
72 char *p = strchr(reply+1,'\r');
73 long long bulklen;
74
75 string2ll(reply+1,p-reply-1,&bulklen);
379789cc 76 if (bulklen == -1) {
82c6b825 77 lua_pushboolean(lua,0);
532e0f5d 78 return p+2;
79 } else {
80 lua_pushlstring(lua,p+2,bulklen);
81 return p+2+bulklen+2;
82 }
83}
84
85char *redisProtocolToLuaType_Status(lua_State *lua, char *reply) {
86 char *p = strchr(reply+1,'\r');
87
0d916763 88 lua_newtable(lua);
89 lua_pushstring(lua,"ok");
532e0f5d 90 lua_pushlstring(lua,reply+1,p-reply-1);
0d916763 91 lua_settable(lua,-3);
532e0f5d 92 return p+2;
93}
94
3791000f 95char *redisProtocolToLuaType_Error(lua_State *lua, char *reply) {
96 char *p = strchr(reply+1,'\r');
97
98 lua_newtable(lua);
99 lua_pushstring(lua,"err");
100 lua_pushlstring(lua,reply+1,p-reply-1);
101 lua_settable(lua,-3);
102 return p+2;
103}
104
105char *redisProtocolToLuaType_MultiBulk(lua_State *lua, char *reply) {
106 char *p = strchr(reply+1,'\r');
107 long long mbulklen;
108 int j = 0;
109
3791000f 110 string2ll(reply+1,p-reply-1,&mbulklen);
111 p += 2;
112 if (mbulklen == -1) {
82c6b825 113 lua_pushboolean(lua,0);
3791000f 114 return p;
115 }
3791000f 116 lua_newtable(lua);
117 for (j = 0; j < mbulklen; j++) {
10a6da7a 118 lua_pushnumber(lua,j+1);
3791000f 119 p = redisProtocolToLuaType(lua,p);
120 lua_settable(lua,-3);
121 }
122 return p;
123}
124
379789cc 125void luaPushError(lua_State *lua, char *error) {
126 lua_newtable(lua);
127 lua_pushstring(lua,"err");
128 lua_pushstring(lua, error);
129 lua_settable(lua,-3);
130}
131
548efd91 132/* Sort the array currently in the stack. We do this to make the output
133 * of commands like KEYS or SMEMBERS something deterministic when called
134 * from Lua (to play well with AOf/replication).
135 *
136 * The array is sorted using table.sort itself, and assuming all the
137 * list elements are strings. */
138void luaSortArray(lua_State *lua) {
139 /* Initial Stack: array */
140 lua_getglobal(lua,"table");
141 lua_pushstring(lua,"sort");
142 lua_gettable(lua,-2); /* Stack: array, table, table.sort */
143 lua_pushvalue(lua,-3); /* Stack: array, table, table.sort, array */
2c861050 144 if (lua_pcall(lua,1,0,0)) {
145 /* Stack: array, table, error */
146
147 /* We are not interested in the error, we assume that the problem is
148 * that there are 'false' elements inside the array, so we try
149 * again with a slower function but able to handle this case, that
150 * is: table.sort(table, __redis__compare_helper) */
151 lua_pop(lua,1); /* Stack: array, table */
152 lua_pushstring(lua,"sort"); /* Stack: array, table, sort */
153 lua_gettable(lua,-2); /* Stack: array, table, table.sort */
154 lua_pushvalue(lua,-3); /* Stack: array, table, table.sort, array */
155 lua_getglobal(lua,"__redis__compare_helper");
156 /* Stack: array, table, table.sort, array, __redis__compare_helper */
157 lua_call(lua,2,0);
158 }
159 /* Stack: array (sorted), table */
548efd91 160 lua_pop(lua,1); /* Stack: array (sorted) */
161}
162
9ed32ba0 163int luaRedisGenericCommand(lua_State *lua, int raise_error) {
0f1d64ca 164 int j, argc = lua_gettop(lua);
165 struct redisCommand *cmd;
166 robj **argv;
167 redisClient *c = server.lua_client;
168 sds reply;
169
edfaa64f 170 /* Require at least one argument */
171 if (argc == 0) {
172 luaPushError(lua,
173 "Please specify at least one argument for redis.call()");
174 return 1;
175 }
176
532e0f5d 177 /* Build the arguments vector */
0f1d64ca 178 argv = zmalloc(sizeof(robj*)*argc);
379789cc 179 for (j = 0; j < argc; j++) {
180 if (!lua_isstring(lua,j+1)) break;
532e0f5d 181 argv[j] = createStringObject((char*)lua_tostring(lua,j+1),
182 lua_strlen(lua,j+1));
379789cc 183 }
184
185 /* Check if one of the arguments passed by the Lua script
186 * is not a string or an integer (lua_isstring() return true for
187 * integers as well). */
188 if (j != argc) {
189 j--;
190 while (j >= 0) {
191 decrRefCount(argv[j]);
192 j--;
193 }
194 zfree(argv);
195 luaPushError(lua,
196 "Lua redis() command arguments must be strings or integers");
197 return 1;
198 }
0f1d64ca 199
15ef6053 200 /* Setup our fake client for command execution */
201 c->argv = argv;
202 c->argc = argc;
203
0f1d64ca 204 /* Command lookup */
205 cmd = lookupCommand(argv[0]->ptr);
3791000f 206 if (!cmd || ((cmd->arity > 0 && cmd->arity != argc) ||
207 (argc < -cmd->arity)))
208 {
3791000f 209 if (cmd)
379789cc 210 luaPushError(lua,
3791000f 211 "Wrong number of args calling Redis command From Lua script");
212 else
379789cc 213 luaPushError(lua,"Unknown Redis command called from Lua script");
15ef6053 214 goto cleanup;
0f1d64ca 215 }
532e0f5d 216
05406168 217 /* There are commands that are not allowed inside scripts. */
15ef6053 218 if (cmd->flags & REDIS_CMD_NOSCRIPT) {
219 luaPushError(lua, "This Redis command is not allowed from scripts");
220 goto cleanup;
221 }
222
05406168 223 /* Write commands are forbidden against read-only slaves, or if a
224 * command marked as non-deterministic was already called in the context
225 * of this script. */
226 if (cmd->flags & REDIS_CMD_WRITE) {
227 if (server.lua_random_dirty) {
228 luaPushError(lua,
229 "Write commands not allowed after non deterministic commands");
230 goto cleanup;
231 } else if (server.masterhost && server.repl_slave_ro &&
232 !(server.lua_caller->flags & REDIS_MASTER))
233 {
234 luaPushError(lua, shared.roslaveerr->ptr);
235 goto cleanup;
236 } else if (server.stop_writes_on_bgsave_err &&
237 server.saveparamslen > 0 &&
238 server.lastbgsave_status == REDIS_ERR)
239 {
240 luaPushError(lua, shared.bgsaveerr->ptr);
241 goto cleanup;
242 }
243 }
244
245 /* If we reached the memory limit configured via maxmemory, commands that
246 * could enlarge the memory usage are not allowed, but only if this is the
247 * first write in the context of this script, otherwise we can't stop
248 * in the middle. */
249 if (server.maxmemory && server.lua_write_dirty == 0 &&
250 (cmd->flags & REDIS_CMD_DENYOOM))
251 {
252 if (freeMemoryIfNeeded() == REDIS_ERR) {
253 luaPushError(lua, shared.oomerr->ptr);
254 goto cleanup;
255 }
9f772cc2 256 }
257
258 if (cmd->flags & REDIS_CMD_RANDOM) server.lua_random_dirty = 1;
4ab8695d 259 if (cmd->flags & REDIS_CMD_WRITE) server.lua_write_dirty = 1;
9f772cc2 260
15ef6053 261 /* Run the command */
ce8b772b 262 c->cmd = cmd;
263 call(c,REDIS_CALL_SLOWLOG | REDIS_CALL_STATS);
0f1d64ca 264
265 /* Convert the result of the Redis command into a suitable Lua type.
266 * The first thing we need is to create a single string from the client
267 * output buffers. */
268 reply = sdsempty();
269 if (c->bufpos) {
7156f43c 270 reply = sdscatlen(reply,c->buf,c->bufpos);
0f1d64ca 271 c->bufpos = 0;
272 }
273 while(listLength(c->reply)) {
274 robj *o = listNodeValue(listFirst(c->reply));
275
09ab5591 276 reply = sdscatlen(reply,o->ptr,sdslen(o->ptr));
0f1d64ca 277 listDelNode(c->reply,listFirst(c->reply));
278 }
9ed32ba0 279 if (raise_error && reply[0] != '-') raise_error = 0;
532e0f5d 280 redisProtocolToLuaType(lua,reply);
548efd91 281 /* Sort the output array if needed, assuming it is a non-null multi bulk
282 * reply as expected. */
283 if ((cmd->flags & REDIS_CMD_SORT_FOR_SCRIPT) &&
284 (reply[0] == '*' && reply[1] != '-')) {
2c861050 285 /* Skip this step if command is SORT but output was already sorted */
286 if (cmd->proc != sortCommand || server.sort_dontsort)
287 luaSortArray(lua);
548efd91 288 }
7156f43c 289 sdsfree(reply);
42a239b8 290 c->reply_bytes = 0;
0f1d64ca 291
15ef6053 292cleanup:
0f1d64ca 293 /* Clean up. Command code may have changed argv/argc so we use the
294 * argv/argc of the client instead of the local variables. */
295 for (j = 0; j < c->argc; j++)
296 decrRefCount(c->argv[j]);
297 zfree(c->argv);
298
9ed32ba0 299 if (raise_error) {
300 /* If we are here we should have an error in the stack, in the
301 * form of a table with an "err" field. Extract the string to
302 * return the plain error. */
303 lua_pushstring(lua,"err");
304 lua_gettable(lua,-2);
305 return lua_error(lua);
306 }
0f1d64ca 307 return 1;
308}
309
9ed32ba0 310int luaRedisCallCommand(lua_State *lua) {
311 return luaRedisGenericCommand(lua,1);
312}
313
314int luaRedisPCallCommand(lua_State *lua) {
315 return luaRedisGenericCommand(lua,0);
316}
317
2f2e6ad4
NF
318/* This adds redis.sha1hex(string) to Lua scripts using the same hashing
319 * function used for sha1ing lua scripts. */
320int luaRedisSha1hexCommand(lua_State *lua) {
321 int argc = lua_gettop(lua);
322 char digest[41];
323 size_t len;
324 char *s;
325
326 if (argc != 1) {
327 luaPushError(lua, "wrong number of arguments");
328 return 1;
329 }
330
331 s = (char*)lua_tolstring(lua,1,&len);
332 sha1hex(digest,s,len);
333 lua_pushstring(lua,digest);
334 return 1;
335}
336
288f811f 337int luaLogCommand(lua_State *lua) {
338 int j, argc = lua_gettop(lua);
339 int level;
340 sds log;
341
342 if (argc < 2) {
343 luaPushError(lua, "redis.log() requires two arguments or more.");
344 return 1;
345 } else if (!lua_isnumber(lua,-argc)) {
e927a246 346 luaPushError(lua, "First argument must be a number (log level).");
288f811f 347 return 1;
348 }
349 level = lua_tonumber(lua,-argc);
e927a246 350 if (level < REDIS_DEBUG || level > REDIS_WARNING) {
288f811f 351 luaPushError(lua, "Invalid debug level.");
352 return 1;
353 }
354
355 /* Glue together all the arguments */
356 log = sdsempty();
357 for (j = 1; j < argc; j++) {
358 size_t len;
359 char *s;
360
361 s = (char*)lua_tolstring(lua,(-argc)+j,&len);
362 if (s) {
363 if (j != 1) log = sdscatlen(log," ",1);
364 log = sdscatlen(log,s,len);
365 }
366 }
367 redisLogRaw(level,log);
368 sdsfree(log);
369 return 0;
370}
371
eeffcf38 372void luaMaskCountHook(lua_State *lua, lua_Debug *ar) {
373 long long elapsed;
374 REDIS_NOTUSED(ar);
115e3ff3 375 REDIS_NOTUSED(lua);
eeffcf38 376
eeffcf38 377 elapsed = (ustime()/1000) - server.lua_time_start;
115e3ff3 378 if (elapsed >= server.lua_time_limit && server.lua_timedout == 0) {
4ab8695d 379 redisLog(REDIS_WARNING,"Lua slow script detected: still in execution after %lld milliseconds. You can try killing the script using the SCRIPT KILL command.",elapsed);
115e3ff3 380 server.lua_timedout = 1;
4ab8695d 381 /* Once the script timeouts we reenter the event loop to permit others
382 * to call SCRIPT KILL or SHUTDOWN NOSAVE if needed. For this reason
383 * we need to mask the client executing the script from the event loop.
384 * If we don't do that the client may disconnect and could no longer be
385 * here when the EVAL command will return. */
386 aeDeleteFileEvent(server.el, server.lua_caller->fd, AE_READABLE);
eeffcf38 387 }
115e3ff3 388 if (server.lua_timedout)
389 aeProcessEvents(server.el, AE_FILE_EVENTS|AE_DONT_WAIT);
4ab8695d 390 if (server.lua_kill) {
391 redisLog(REDIS_WARNING,"Lua script killed by user with SCRIPT KILL.");
392 lua_pushstring(lua,"Script killed by user with SCRIPT KILL...");
393 lua_error(lua);
394 }
eeffcf38 395}
396
002d5626 397void luaLoadLib(lua_State *lua, const char *libname, lua_CFunction luafunc) {
398 lua_pushcfunction(lua, luafunc);
399 lua_pushstring(lua, libname);
400 lua_call(lua, 1, 0);
401}
402
15108778 403LUALIB_API int (luaopen_cjson) (lua_State *L);
2f75bbab 404LUALIB_API int (luaopen_struct) (lua_State *L);
63505e0b 405LUALIB_API int (luaopen_cmsgpack) (lua_State *L);
15108778 406
002d5626 407void luaLoadLibraries(lua_State *lua) {
408 luaLoadLib(lua, "", luaopen_base);
409 luaLoadLib(lua, LUA_TABLIBNAME, luaopen_table);
410 luaLoadLib(lua, LUA_STRLIBNAME, luaopen_string);
411 luaLoadLib(lua, LUA_MATHLIBNAME, luaopen_math);
412 luaLoadLib(lua, LUA_DBLIBNAME, luaopen_debug);
2f75bbab 413 luaLoadLib(lua, "cjson", luaopen_cjson);
414 luaLoadLib(lua, "struct", luaopen_struct);
63505e0b 415 luaLoadLib(lua, "cmsgpack", luaopen_cmsgpack);
002d5626 416
417#if 0 /* Stuff that we don't load currently, for sandboxing concerns. */
418 luaLoadLib(lua, LUA_LOADLIBNAME, luaopen_package);
419 luaLoadLib(lua, LUA_OSLIBNAME, luaopen_os);
420#endif
421}
422
537dafab 423/* Remove a functions that we don't want to expose to the Redis scripting
424 * environment. */
425void luaRemoveUnsupportedFunctions(lua_State *lua) {
426 lua_pushnil(lua);
427 lua_setglobal(lua,"loadfile");
428}
429
3e6a4463 430/* This function installs metamethods in the global table _G that prevent
431 * the creation of globals accidentally.
432 *
433 * It should be the last to be called in the scripting engine initialization
97cab309 434 * sequence, because it may interact with creation of globals. */
3e6a4463 435void scriptingEnableGlobalsProtection(lua_State *lua) {
436 char *s[32];
430602b2 437 sds code = sdsempty();
3e6a4463 438 int j = 0;
430602b2 439
3e6a4463 440 /* strict.lua from: http://metalua.luaforge.net/src/lib/strict.lua.html.
441 * Modified to be adapted to Redis. */
6255a5ae 442 s[j++]="local mt = {}\n";
3e6a4463 443 s[j++]="setmetatable(_G, mt)\n";
3e6a4463 444 s[j++]="mt.__newindex = function (t, n, v)\n";
d2906893 445 s[j++]=" if debug.getinfo(2) then\n";
3e6a4463 446 s[j++]=" local w = debug.getinfo(2, \"S\").what\n";
447 s[j++]=" if w ~= \"main\" and w ~= \"C\" then\n";
97cab309 448 s[j++]=" error(\"Script attempted to create global variable '\"..tostring(n)..\"'\", 2)\n";
3e6a4463 449 s[j++]=" end\n";
3e6a4463 450 s[j++]=" end\n";
451 s[j++]=" rawset(t, n, v)\n";
452 s[j++]="end\n";
453 s[j++]="mt.__index = function (t, n)\n";
d2906893 454 s[j++]=" if debug.getinfo(2) and debug.getinfo(2, \"S\").what ~= \"C\" then\n";
c9853f53 455 s[j++]=" error(\"Script attempted to access unexisting global variable '\"..tostring(n)..\"'\", 2)\n";
3e6a4463 456 s[j++]=" end\n";
457 s[j++]=" return rawget(t, n)\n";
458 s[j++]="end\n";
3e6a4463 459 s[j++]=NULL;
460
461 for (j = 0; s[j] != NULL; j++) code = sdscatlen(code,s[j],strlen(s[j]));
9a2dd1ef 462 luaL_loadbuffer(lua,code,sdslen(code),"@enable_strict_lua");
430602b2 463 lua_pcall(lua,0,0,0);
464 sdsfree(code);
465}
466
070e3945 467/* Initialize the scripting environment.
468 * It is possible to call this function to reset the scripting environment
469 * assuming that we call scriptingRelease() before.
470 * See scriptingReset() for more information. */
7585836e 471void scriptingInit(void) {
472 lua_State *lua = lua_open();
537dafab 473
002d5626 474 luaLoadLibraries(lua);
537dafab 475 luaRemoveUnsupportedFunctions(lua);
0f1d64ca 476
4dd444bb 477 /* Initialize a dictionary we use to map SHAs to scripts.
478 * This is useful for replication, as we need to replicate EVALSHA
479 * as EVAL, so we need to remember the associated script. */
480 server.lua_scripts = dictCreate(&dbDictType,NULL);
481
288f811f 482 /* Register the redis commands table and fields */
483 lua_newtable(lua);
484
485 /* redis.call */
486 lua_pushstring(lua,"call");
9ed32ba0 487 lua_pushcfunction(lua,luaRedisCallCommand);
488 lua_settable(lua,-3);
489
490 /* redis.pcall */
491 lua_pushstring(lua,"pcall");
492 lua_pushcfunction(lua,luaRedisPCallCommand);
288f811f 493 lua_settable(lua,-3);
494
495 /* redis.log and log levels. */
496 lua_pushstring(lua,"log");
497 lua_pushcfunction(lua,luaLogCommand);
498 lua_settable(lua,-3);
499
500 lua_pushstring(lua,"LOG_DEBUG");
501 lua_pushnumber(lua,REDIS_DEBUG);
502 lua_settable(lua,-3);
503
504 lua_pushstring(lua,"LOG_VERBOSE");
505 lua_pushnumber(lua,REDIS_VERBOSE);
506 lua_settable(lua,-3);
507
508 lua_pushstring(lua,"LOG_NOTICE");
509 lua_pushnumber(lua,REDIS_NOTICE);
510 lua_settable(lua,-3);
511
512 lua_pushstring(lua,"LOG_WARNING");
513 lua_pushnumber(lua,REDIS_WARNING);
514 lua_settable(lua,-3);
515
2f2e6ad4
NF
516 /* redis.sha1hex */
517 lua_pushstring(lua, "sha1hex");
518 lua_pushcfunction(lua, luaRedisSha1hexCommand);
519 lua_settable(lua, -3);
520
288f811f 521 /* Finally set the table as 'redis' global var. */
00b7541b 522 lua_setglobal(lua,"redis");
0f1d64ca 523
e108bab0 524 /* Replace math.random and math.randomseed with our implementations. */
525 lua_getglobal(lua,"math");
526
527 lua_pushstring(lua,"random");
528 lua_pushcfunction(lua,redis_math_random);
529 lua_settable(lua,-3);
530
531 lua_pushstring(lua,"randomseed");
532 lua_pushcfunction(lua,redis_math_randomseed);
533 lua_settable(lua,-3);
534
535 lua_setglobal(lua,"math");
536
2c861050 537 /* Add a helper funciton that we use to sort the multi bulk output of non
538 * deterministic commands, when containing 'false' elements. */
539 {
540 char *compare_func = "function __redis__compare_helper(a,b)\n"
541 " if a == false then a = '' end\n"
542 " if b == false then b = '' end\n"
543 " return a<b\n"
544 "end\n";
9a2dd1ef 545 luaL_loadbuffer(lua,compare_func,strlen(compare_func),"@cmp_func_def");
2c861050 546 lua_pcall(lua,0,0,0);
547 }
548
0f1d64ca 549 /* Create the (non connected) client that we use to execute Redis commands
070e3945 550 * inside the Lua interpreter.
551 * Note: there is no need to create it again when this function is called
552 * by scriptingReset(). */
553 if (server.lua_client == NULL) {
554 server.lua_client = createClient(-1);
555 server.lua_client->flags |= REDIS_LUA_CLIENT;
556 }
0f1d64ca 557
430602b2 558 /* Lua beginners ofter don't use "local", this is likely to introduce
559 * subtle bugs in their code. To prevent problems we protect accesses
560 * to global variables. */
97cab309 561 scriptingEnableGlobalsProtection(lua);
430602b2 562
7585836e 563 server.lua = lua;
564}
565
070e3945 566/* Release resources related to Lua scripting.
567 * This function is used in order to reset the scripting environment. */
568void scriptingRelease(void) {
569 dictRelease(server.lua_scripts);
570 lua_close(server.lua);
571}
572
573void scriptingReset(void) {
574 scriptingRelease();
575 scriptingInit();
576}
577
2f2e6ad4
NF
578/* Perform the SHA1 of the input string. We use this both for hasing script
579 * bodies in order to obtain the Lua function name, and in the implementation
580 * of redis.sha1().
581 *
582 * 'digest' should point to a 41 bytes buffer: 40 for SHA1 converted into an
7585836e 583 * hexadecimal number, plus 1 byte for null term. */
2f2e6ad4 584void sha1hex(char *digest, char *script, size_t len) {
7585836e 585 SHA1_CTX ctx;
586 unsigned char hash[20];
587 char *cset = "0123456789abcdef";
588 int j;
589
590 SHA1Init(&ctx);
591 SHA1Update(&ctx,(unsigned char*)script,len);
592 SHA1Final(hash,&ctx);
593
594 for (j = 0; j < 20; j++) {
595 digest[j*2] = cset[((hash[j]&0xF0)>>4)];
596 digest[j*2+1] = cset[(hash[j]&0xF)];
597 }
598 digest[40] = '\0';
599}
600
601void luaReplyToRedisReply(redisClient *c, lua_State *lua) {
82c6b825 602 int t = lua_type(lua,-1);
7585836e 603
604 switch(t) {
605 case LUA_TSTRING:
82c6b825 606 addReplyBulkCBuffer(c,(char*)lua_tostring(lua,-1),lua_strlen(lua,-1));
7585836e 607 break;
608 case LUA_TBOOLEAN:
82c6b825 609 addReply(c,lua_toboolean(lua,-1) ? shared.cone : shared.nullbulk);
7585836e 610 break;
611 case LUA_TNUMBER:
82c6b825 612 addReplyLongLong(c,(long long)lua_tonumber(lua,-1));
7585836e 613 break;
532e0f5d 614 case LUA_TTABLE:
0d916763 615 /* We need to check if it is an array, an error, or a status reply.
616 * Error are returned as a single element table with 'err' field.
617 * Status replies are returned as single elment table with 'ok' field */
532e0f5d 618 lua_pushstring(lua,"err");
619 lua_gettable(lua,-2);
620 t = lua_type(lua,-1);
621 if (t == LUA_TSTRING) {
3bb818df 622 sds err = sdsnew(lua_tostring(lua,-1));
623 sdsmapchars(err,"\r\n"," ",2);
624 addReplySds(c,sdscatprintf(sdsempty(),"-%s\r\n",err));
625 sdsfree(err);
0d916763 626 lua_pop(lua,2);
627 return;
628 }
629
630 lua_pop(lua,1);
631 lua_pushstring(lua,"ok");
632 lua_gettable(lua,-2);
633 t = lua_type(lua,-1);
634 if (t == LUA_TSTRING) {
3bb818df 635 sds ok = sdsnew(lua_tostring(lua,-1));
636 sdsmapchars(ok,"\r\n"," ",2);
637 addReplySds(c,sdscatprintf(sdsempty(),"+%s\r\n",ok));
638 sdsfree(ok);
532e0f5d 639 lua_pop(lua,1);
640 } else {
641 void *replylen = addDeferredMultiBulkLength(c);
642 int j = 1, mbulklen = 0;
643
0d916763 644 lua_pop(lua,1); /* Discard the 'ok' field value we popped */
532e0f5d 645 while(1) {
646 lua_pushnumber(lua,j++);
647 lua_gettable(lua,-2);
648 t = lua_type(lua,-1);
649 if (t == LUA_TNIL) {
650 lua_pop(lua,1);
651 break;
532e0f5d 652 }
82c6b825 653 luaReplyToRedisReply(c, lua);
654 mbulklen++;
532e0f5d 655 }
656 setDeferredMultiBulkLength(c,replylen,mbulklen);
657 }
658 break;
7585836e 659 default:
660 addReply(c,shared.nullbulk);
661 }
662 lua_pop(lua,1);
663}
664
4ae5b5e1 665/* Set an array of Redis String Objects as a Lua array (table) stored into a
666 * global variable. */
667void luaSetGlobalArray(lua_State *lua, char *var, robj **elev, int elec) {
668 int j;
669
670 lua_newtable(lua);
671 for (j = 0; j < elec; j++) {
672 lua_pushlstring(lua,(char*)elev[j]->ptr,sdslen(elev[j]->ptr));
673 lua_rawseti(lua,-2,j+1);
674 }
675 lua_setglobal(lua,var);
676}
677
a9b07ac4 678/* Define a lua function with the specified function name and body.
679 * The function name musts be a 2 characters long string, since all the
680 * functions we defined in the Lua context are in the form:
681 *
682 * f_<hex sha1 sum>
683 *
684 * On success REDIS_OK is returned, and nothing is left on the Lua stack.
685 * On error REDIS_ERR is returned and an appropriate error is set in the
686 * client context. */
687int luaCreateFunction(redisClient *c, lua_State *lua, char *funcname, robj *body) {
688 sds funcdef = sdsempty();
689
a9b07ac4 690 funcdef = sdscat(funcdef,"function ");
691 funcdef = sdscatlen(funcdef,funcname,42);
4d776dba 692 funcdef = sdscatlen(funcdef,"() ",3);
a9b07ac4 693 funcdef = sdscatlen(funcdef,body->ptr,sdslen(body->ptr));
4d776dba 694 funcdef = sdscatlen(funcdef," end",4);
a9b07ac4 695
9a2dd1ef 696 if (luaL_loadbuffer(lua,funcdef,sdslen(funcdef),"@user_script")) {
a9b07ac4 697 addReplyErrorFormat(c,"Error compiling script (new function): %s\n",
698 lua_tostring(lua,-1));
699 lua_pop(lua,1);
700 sdsfree(funcdef);
701 return REDIS_ERR;
702 }
703 sdsfree(funcdef);
704 if (lua_pcall(lua,0,0,0)) {
705 addReplyErrorFormat(c,"Error running script (new function): %s\n",
706 lua_tostring(lua,-1));
707 lua_pop(lua,1);
708 return REDIS_ERR;
709 }
710
711 /* We also save a SHA1 -> Original script map in a dictionary
712 * so that we can replicate / write in the AOF all the
713 * EVALSHA commands as EVAL using the original script. */
714 {
715 int retval = dictAdd(server.lua_scripts,
716 sdsnewlen(funcname+2,40),body);
717 redisAssertWithInfo(c,NULL,retval == DICT_OK);
718 incrRefCount(body);
719 }
720 return REDIS_OK;
721}
722
7229d60d 723void evalGenericCommand(redisClient *c, int evalsha) {
7585836e 724 lua_State *lua = server.lua;
725 char funcname[43];
4ae5b5e1 726 long long numkeys;
77a75fde 727 int delhook = 0;
4ae5b5e1 728
e108bab0 729 /* We want the same PRNG sequence at every call so that our PRNG is
730 * not affected by external state. */
731 redisSrand48(0);
732
9f772cc2 733 /* We set this flag to zero to remember that so far no random command
734 * was called. This way we can allow the user to call commands like
735 * SRANDMEMBER or RANDOMKEY from Lua scripts as far as no write command
736 * is called (otherwise the replication and AOF would end with non
737 * deterministic sequences).
738 *
739 * Thanks to this flag we'll raise an error every time a write command
740 * is called after a random command was used. */
741 server.lua_random_dirty = 0;
4ab8695d 742 server.lua_write_dirty = 0;
9f772cc2 743
4ae5b5e1 744 /* Get the number of arguments that are keys */
745 if (getLongLongFromObjectOrReply(c,c->argv[2],&numkeys,NULL) != REDIS_OK)
746 return;
747 if (numkeys > (c->argc - 3)) {
748 addReplyError(c,"Number of keys can't be greater than number of args");
749 return;
750 }
7585836e 751
752 /* We obtain the script SHA1, then check if this function is already
753 * defined into the Lua state */
754 funcname[0] = 'f';
755 funcname[1] = '_';
7229d60d 756 if (!evalsha) {
757 /* Hash the code if this is an EVAL call */
2f2e6ad4 758 sha1hex(funcname+2,c->argv[1]->ptr,sdslen(c->argv[1]->ptr));
7229d60d 759 } else {
760 /* We already have the SHA if it is a EVALSHA */
761 int j;
762 char *sha = c->argv[1]->ptr;
763
764 for (j = 0; j < 40; j++)
765 funcname[j+2] = tolower(sha[j]);
766 funcname[42] = '\0';
767 }
768
a9b07ac4 769 /* Try to lookup the Lua function */
7585836e 770 lua_getglobal(lua, funcname);
771 if (lua_isnil(lua,1)) {
e8c993f0 772 lua_pop(lua,1); /* remove the nil from the stack */
7229d60d 773 /* Function not defined... let's define it if we have the
774 * body of the funciton. If this is an EVALSHA call we can just
775 * return an error. */
776 if (evalsha) {
777 addReply(c, shared.noscripterr);
7229d60d 778 return;
779 }
a9b07ac4 780 if (luaCreateFunction(c,lua,funcname,c->argv[1]) == REDIS_ERR) return;
781 /* Now the following is guaranteed to return non nil */
7585836e 782 lua_getglobal(lua, funcname);
a9b07ac4 783 redisAssert(!lua_isnil(lua,1));
7585836e 784 }
4ae5b5e1 785
786 /* Populate the argv and keys table accordingly to the arguments that
787 * EVAL received. */
788 luaSetGlobalArray(lua,"KEYS",c->argv+3,numkeys);
789 luaSetGlobalArray(lua,"ARGV",c->argv+3+numkeys,c->argc-3-numkeys);
c2a7dd85 790
791 /* Select the right DB in the context of the Lua client */
792 selectDb(server.lua_client,c->db->id);
7585836e 793
da386cdf 794 /* Set an hook in order to be able to stop the script execution if it
795 * is running for too much time.
796 * We set the hook only if the time limit is enabled as the hook will
797 * make the Lua script execution slower. */
77a75fde 798 server.lua_caller = c;
799 server.lua_time_start = ustime()/1000;
800 server.lua_kill = 0;
115e3ff3 801 if (server.lua_time_limit > 0 && server.masterhost == NULL) {
da386cdf 802 lua_sethook(lua,luaMaskCountHook,LUA_MASKCOUNT,100000);
77a75fde 803 delhook = 1;
da386cdf 804 }
805
7585836e 806 /* At this point whatever this script was never seen before or if it was
807 * already defined, we can call it. We have zero arguments and expect
808 * a single return value. */
809 if (lua_pcall(lua,0,1,0)) {
77a75fde 810 if (delhook) lua_sethook(lua,luaMaskCountHook,0,0); /* Disable hook */
4ab8695d 811 if (server.lua_timedout) {
812 server.lua_timedout = 0;
813 /* Restore the readable handler that was unregistered when the
814 * script timeout was detected. */
815 aeCreateFileEvent(server.el,c->fd,AE_READABLE,
816 readQueryFromClient,c);
817 }
818 server.lua_caller = NULL;
c2a7dd85 819 selectDb(c,server.lua_client->db->id); /* set DB ID from Lua client */
7585836e 820 addReplyErrorFormat(c,"Error running script (call to %s): %s\n",
821 funcname, lua_tostring(lua,-1));
822 lua_pop(lua,1);
40531be0 823 lua_gc(lua,LUA_GCCOLLECT,0);
7585836e 824 return;
825 }
77a75fde 826 if (delhook) lua_sethook(lua,luaMaskCountHook,0,0); /* Disable hook */
115e3ff3 827 server.lua_timedout = 0;
4ab8695d 828 server.lua_caller = NULL;
c2a7dd85 829 selectDb(c,server.lua_client->db->id); /* set DB ID from Lua client */
7585836e 830 luaReplyToRedisReply(c,lua);
40531be0 831 lua_gc(lua,LUA_GCSTEP,1);
4dd444bb 832
833 /* If we have slaves attached we want to replicate this command as
834 * EVAL instead of EVALSHA. We do this also in the AOF as currently there
835 * is no easy way to propagate a command in a different way in the AOF
836 * and in the replication link.
837 *
838 * IMPROVEMENT POSSIBLE:
839 * 1) Replicate this command as EVALSHA in the AOF.
840 * 2) Remember what slave already received a given script, and replicate
841 * the EVALSHA against this slaves when possible.
842 */
843 if (evalsha) {
844 robj *script = dictFetchValue(server.lua_scripts,c->argv[1]->ptr);
845
eab0e26e 846 redisAssertWithInfo(c,NULL,script != NULL);
4dd444bb 847 rewriteClientCommandArgument(c,0,
848 resetRefCount(createStringObject("EVAL",4)));
849 rewriteClientCommandArgument(c,1,script);
850 }
7585836e 851}
7229d60d 852
853void evalCommand(redisClient *c) {
854 evalGenericCommand(c,0);
855}
856
857void evalShaCommand(redisClient *c) {
858 if (sdslen(c->argv[1]->ptr) != 40) {
859 /* We know that a match is not possible if the provided SHA is
860 * not the right length. So we return an error ASAP, this way
861 * evalGenericCommand() can be implemented without string length
862 * sanity check */
863 addReply(c, shared.noscripterr);
864 return;
865 }
866 evalGenericCommand(c,1);
867}
e108bab0 868
869/* We replace math.random() with our implementation that is not affected
870 * by specific libc random() implementations and will output the same sequence
871 * (for the same seed) in every arch. */
872
873/* The following implementation is the one shipped with Lua itself but with
874 * rand() replaced by redisLrand48(). */
875int redis_math_random (lua_State *L) {
876 /* the `%' avoids the (rare) case of r==1, and is needed also because on
877 some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */
878 lua_Number r = (lua_Number)(redisLrand48()%REDIS_LRAND48_MAX) /
879 (lua_Number)REDIS_LRAND48_MAX;
880 switch (lua_gettop(L)) { /* check number of arguments */
881 case 0: { /* no arguments */
882 lua_pushnumber(L, r); /* Number between 0 and 1 */
883 break;
884 }
885 case 1: { /* only upper limit */
886 int u = luaL_checkint(L, 1);
887 luaL_argcheck(L, 1<=u, 1, "interval is empty");
888 lua_pushnumber(L, floor(r*u)+1); /* int between 1 and `u' */
889 break;
890 }
891 case 2: { /* lower and upper limits */
892 int l = luaL_checkint(L, 1);
893 int u = luaL_checkint(L, 2);
894 luaL_argcheck(L, l<=u, 2, "interval is empty");
895 lua_pushnumber(L, floor(r*(u-l+1))+l); /* int between `l' and `u' */
896 break;
897 }
898 default: return luaL_error(L, "wrong number of arguments");
899 }
900 return 1;
901}
902
903int redis_math_randomseed (lua_State *L) {
904 redisSrand48(luaL_checkint(L, 1));
905 return 0;
906}
070e3945 907
908/* ---------------------------------------------------------------------------
909 * SCRIPT command for script environment introspection and control
910 * ------------------------------------------------------------------------- */
911
912void scriptCommand(redisClient *c) {
913 if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"flush")) {
914 scriptingReset();
915 addReply(c,shared.ok);
916 server.dirty++; /* Replicating this command is a good idea. */
917 } else if (c->argc >= 2 && !strcasecmp(c->argv[1]->ptr,"exists")) {
918 int j;
919
920 addReplyMultiBulkLen(c, c->argc-2);
921 for (j = 2; j < c->argc; j++) {
922 if (dictFind(server.lua_scripts,c->argv[j]->ptr))
923 addReply(c,shared.cone);
924 else
925 addReply(c,shared.czero);
926 }
a9b07ac4 927 } else if (c->argc == 3 && !strcasecmp(c->argv[1]->ptr,"load")) {
a9b07ac4 928 char funcname[43];
e8c993f0 929 sds sha;
a9b07ac4 930
931 funcname[0] = 'f';
932 funcname[1] = '_';
2f2e6ad4 933 sha1hex(funcname+2,c->argv[2]->ptr,sdslen(c->argv[2]->ptr));
e8c993f0 934 sha = sdsnewlen(funcname+2,40);
935 if (dictFind(server.lua_scripts,sha) == NULL) {
936 if (luaCreateFunction(c,server.lua,funcname,c->argv[2])
937 == REDIS_ERR) {
938 sdsfree(sha);
939 return;
940 }
941 }
e5abf6ef 942 addReplyBulkCBuffer(c,funcname+2,40);
e8c993f0 943 sdsfree(sha);
4ab8695d 944 } else if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"kill")) {
945 if (server.lua_caller == NULL) {
946 addReplyError(c,"No scripts in execution right now.");
947 } else if (server.lua_write_dirty) {
948 addReplyError(c, "Sorry the script already executed write commands against the dataset. You can either wait the script termination or kill the server in an hard way using the SHUTDOWN NOSAVE command.");
949 } else {
950 server.lua_kill = 1;
951 addReply(c,shared.ok);
952 }
070e3945 953 } else {
954 addReplyError(c, "Unknown SCRIPT subcommand or wrong # of args.");
955 }
956}