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