2 * Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of Redis nor the names of its contributors may be used
14 * to endorse or promote products derived from this software without
15 * specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
40 char *redisProtocolToLuaType_Int(lua_State
*lua
, char *reply
);
41 char *redisProtocolToLuaType_Bulk(lua_State
*lua
, char *reply
);
42 char *redisProtocolToLuaType_Status(lua_State
*lua
, char *reply
);
43 char *redisProtocolToLuaType_Error(lua_State
*lua
, char *reply
);
44 char *redisProtocolToLuaType_MultiBulk(lua_State
*lua
, char *reply
);
45 int redis_math_random (lua_State
*L
);
46 int redis_math_randomseed (lua_State
*L
);
47 void sha1hex(char *digest
, char *script
, size_t len
);
49 /* Take a Redis reply in the Redis protocol format and convert it into a
50 * Lua type. Thanks to this function, and the introduction of not connected
51 * clients, it is trvial to implement the redis() lua function.
53 * Basically we take the arguments, execute the Redis command in the context
54 * of a non connected client, then take the generated reply and convert it
55 * into a suitable Lua type. With this trick the scripting feature does not
56 * need the introduction of a full Redis internals API. Basically the script
57 * is like a normal client that bypasses all the slow I/O paths.
59 * Note: in this function we do not do any sanity check as the reply is
60 * generated by Redis directly. This allows us to go faster.
61 * The reply string can be altered during the parsing as it is discared
62 * after the conversion is completed.
64 * Errors are returned as a table with a single 'err' field set to the
68 char *redisProtocolToLuaType(lua_State
*lua
, char* reply
) {
73 p
= redisProtocolToLuaType_Int(lua
,reply
);
76 p
= redisProtocolToLuaType_Bulk(lua
,reply
);
79 p
= redisProtocolToLuaType_Status(lua
,reply
);
82 p
= redisProtocolToLuaType_Error(lua
,reply
);
85 p
= redisProtocolToLuaType_MultiBulk(lua
,reply
);
91 char *redisProtocolToLuaType_Int(lua_State
*lua
, char *reply
) {
92 char *p
= strchr(reply
+1,'\r');
95 string2ll(reply
+1,p
-reply
-1,&value
);
96 lua_pushnumber(lua
,(lua_Number
)value
);
100 char *redisProtocolToLuaType_Bulk(lua_State
*lua
, char *reply
) {
101 char *p
= strchr(reply
+1,'\r');
104 string2ll(reply
+1,p
-reply
-1,&bulklen
);
106 lua_pushboolean(lua
,0);
109 lua_pushlstring(lua
,p
+2,bulklen
);
110 return p
+2+bulklen
+2;
114 char *redisProtocolToLuaType_Status(lua_State
*lua
, char *reply
) {
115 char *p
= strchr(reply
+1,'\r');
118 lua_pushstring(lua
,"ok");
119 lua_pushlstring(lua
,reply
+1,p
-reply
-1);
120 lua_settable(lua
,-3);
124 char *redisProtocolToLuaType_Error(lua_State
*lua
, char *reply
) {
125 char *p
= strchr(reply
+1,'\r');
128 lua_pushstring(lua
,"err");
129 lua_pushlstring(lua
,reply
+1,p
-reply
-1);
130 lua_settable(lua
,-3);
134 char *redisProtocolToLuaType_MultiBulk(lua_State
*lua
, char *reply
) {
135 char *p
= strchr(reply
+1,'\r');
139 string2ll(reply
+1,p
-reply
-1,&mbulklen
);
141 if (mbulklen
== -1) {
142 lua_pushboolean(lua
,0);
146 for (j
= 0; j
< mbulklen
; j
++) {
147 lua_pushnumber(lua
,j
+1);
148 p
= redisProtocolToLuaType(lua
,p
);
149 lua_settable(lua
,-3);
154 void luaPushError(lua_State
*lua
, char *error
) {
156 lua_pushstring(lua
,"err");
157 lua_pushstring(lua
, error
);
158 lua_settable(lua
,-3);
161 /* Sort the array currently in the stack. We do this to make the output
162 * of commands like KEYS or SMEMBERS something deterministic when called
163 * from Lua (to play well with AOf/replication).
165 * The array is sorted using table.sort itself, and assuming all the
166 * list elements are strings. */
167 void luaSortArray(lua_State
*lua
) {
168 /* Initial Stack: array */
169 lua_getglobal(lua
,"table");
170 lua_pushstring(lua
,"sort");
171 lua_gettable(lua
,-2); /* Stack: array, table, table.sort */
172 lua_pushvalue(lua
,-3); /* Stack: array, table, table.sort, array */
173 if (lua_pcall(lua
,1,0,0)) {
174 /* Stack: array, table, error */
176 /* We are not interested in the error, we assume that the problem is
177 * that there are 'false' elements inside the array, so we try
178 * again with a slower function but able to handle this case, that
179 * is: table.sort(table, __redis__compare_helper) */
180 lua_pop(lua
,1); /* Stack: array, table */
181 lua_pushstring(lua
,"sort"); /* Stack: array, table, sort */
182 lua_gettable(lua
,-2); /* Stack: array, table, table.sort */
183 lua_pushvalue(lua
,-3); /* Stack: array, table, table.sort, array */
184 lua_getglobal(lua
,"__redis__compare_helper");
185 /* Stack: array, table, table.sort, array, __redis__compare_helper */
188 /* Stack: array (sorted), table */
189 lua_pop(lua
,1); /* Stack: array (sorted) */
192 int luaRedisGenericCommand(lua_State
*lua
, int raise_error
) {
193 int j
, argc
= lua_gettop(lua
);
194 struct redisCommand
*cmd
;
196 redisClient
*c
= server
.lua_client
;
199 /* Require at least one argument */
202 "Please specify at least one argument for redis.call()");
206 /* Build the arguments vector */
207 argv
= zmalloc(sizeof(robj
*)*argc
);
208 for (j
= 0; j
< argc
; j
++) {
209 if (!lua_isstring(lua
,j
+1)) break;
210 argv
[j
] = createStringObject((char*)lua_tostring(lua
,j
+1),
211 lua_strlen(lua
,j
+1));
214 /* Check if one of the arguments passed by the Lua script
215 * is not a string or an integer (lua_isstring() return true for
216 * integers as well). */
220 decrRefCount(argv
[j
]);
225 "Lua redis() command arguments must be strings or integers");
229 /* Setup our fake client for command execution */
234 cmd
= lookupCommand(argv
[0]->ptr
);
235 if (!cmd
|| ((cmd
->arity
> 0 && cmd
->arity
!= argc
) ||
236 (argc
< -cmd
->arity
)))
240 "Wrong number of args calling Redis command From Lua script");
242 luaPushError(lua
,"Unknown Redis command called from Lua script");
246 /* There are commands that are not allowed inside scripts. */
247 if (cmd
->flags
& REDIS_CMD_NOSCRIPT
) {
248 luaPushError(lua
, "This Redis command is not allowed from scripts");
252 /* Write commands are forbidden against read-only slaves, or if a
253 * command marked as non-deterministic was already called in the context
255 if (cmd
->flags
& REDIS_CMD_WRITE
) {
256 if (server
.lua_random_dirty
) {
258 "Write commands not allowed after non deterministic commands");
260 } else if (server
.masterhost
&& server
.repl_slave_ro
&&
261 !(server
.lua_caller
->flags
& REDIS_MASTER
))
263 luaPushError(lua
, shared
.roslaveerr
->ptr
);
265 } else if (server
.stop_writes_on_bgsave_err
&&
266 server
.saveparamslen
> 0 &&
267 server
.lastbgsave_status
== REDIS_ERR
)
269 luaPushError(lua
, shared
.bgsaveerr
->ptr
);
274 /* If we reached the memory limit configured via maxmemory, commands that
275 * could enlarge the memory usage are not allowed, but only if this is the
276 * first write in the context of this script, otherwise we can't stop
278 if (server
.maxmemory
&& server
.lua_write_dirty
== 0 &&
279 (cmd
->flags
& REDIS_CMD_DENYOOM
))
281 if (freeMemoryIfNeeded() == REDIS_ERR
) {
282 luaPushError(lua
, shared
.oomerr
->ptr
);
287 if (cmd
->flags
& REDIS_CMD_RANDOM
) server
.lua_random_dirty
= 1;
288 if (cmd
->flags
& REDIS_CMD_WRITE
) server
.lua_write_dirty
= 1;
290 /* Run the command */
292 call(c
,REDIS_CALL_SLOWLOG
| REDIS_CALL_STATS
);
294 /* Convert the result of the Redis command into a suitable Lua type.
295 * The first thing we need is to create a single string from the client
299 reply
= sdscatlen(reply
,c
->buf
,c
->bufpos
);
302 while(listLength(c
->reply
)) {
303 robj
*o
= listNodeValue(listFirst(c
->reply
));
305 reply
= sdscatlen(reply
,o
->ptr
,sdslen(o
->ptr
));
306 listDelNode(c
->reply
,listFirst(c
->reply
));
308 if (raise_error
&& reply
[0] != '-') raise_error
= 0;
309 redisProtocolToLuaType(lua
,reply
);
310 /* Sort the output array if needed, assuming it is a non-null multi bulk
311 * reply as expected. */
312 if ((cmd
->flags
& REDIS_CMD_SORT_FOR_SCRIPT
) &&
313 (reply
[0] == '*' && reply
[1] != '-')) {
320 /* Clean up. Command code may have changed argv/argc so we use the
321 * argv/argc of the client instead of the local variables. */
322 for (j
= 0; j
< c
->argc
; j
++)
323 decrRefCount(c
->argv
[j
]);
327 /* If we are here we should have an error in the stack, in the
328 * form of a table with an "err" field. Extract the string to
329 * return the plain error. */
330 lua_pushstring(lua
,"err");
331 lua_gettable(lua
,-2);
332 return lua_error(lua
);
337 int luaRedisCallCommand(lua_State
*lua
) {
338 return luaRedisGenericCommand(lua
,1);
341 int luaRedisPCallCommand(lua_State
*lua
) {
342 return luaRedisGenericCommand(lua
,0);
345 /* This adds redis.sha1hex(string) to Lua scripts using the same hashing
346 * function used for sha1ing lua scripts. */
347 int luaRedisSha1hexCommand(lua_State
*lua
) {
348 int argc
= lua_gettop(lua
);
354 luaPushError(lua
, "wrong number of arguments");
358 s
= (char*)lua_tolstring(lua
,1,&len
);
359 sha1hex(digest
,s
,len
);
360 lua_pushstring(lua
,digest
);
364 /* Returns a table with a single field 'field' set to the string value
365 * passed as argument. This helper function is handy when returning
366 * a Redis Protocol error or status reply from Lua:
368 * return redis.error_reply("ERR Some Error")
369 * return redis.status_reply("ERR Some Error")
371 int luaRedisReturnSingleFieldTable(lua_State
*lua
, char *field
) {
372 if (lua_gettop(lua
) != 1 || lua_type(lua
,-1) != LUA_TSTRING
) {
373 luaPushError(lua
, "wrong number or type of arguments");
378 lua_pushstring(lua
, field
);
379 lua_pushvalue(lua
, -3);
380 lua_settable(lua
, -3);
384 int luaRedisErrorReplyCommand(lua_State
*lua
) {
385 return luaRedisReturnSingleFieldTable(lua
,"err");
388 int luaRedisStatusReplyCommand(lua_State
*lua
) {
389 return luaRedisReturnSingleFieldTable(lua
,"ok");
392 int luaLogCommand(lua_State
*lua
) {
393 int j
, argc
= lua_gettop(lua
);
398 luaPushError(lua
, "redis.log() requires two arguments or more.");
400 } else if (!lua_isnumber(lua
,-argc
)) {
401 luaPushError(lua
, "First argument must be a number (log level).");
404 level
= lua_tonumber(lua
,-argc
);
405 if (level
< REDIS_DEBUG
|| level
> REDIS_WARNING
) {
406 luaPushError(lua
, "Invalid debug level.");
410 /* Glue together all the arguments */
412 for (j
= 1; j
< argc
; j
++) {
416 s
= (char*)lua_tolstring(lua
,(-argc
)+j
,&len
);
418 if (j
!= 1) log
= sdscatlen(log
," ",1);
419 log
= sdscatlen(log
,s
,len
);
422 redisLogRaw(level
,log
);
427 void luaMaskCountHook(lua_State
*lua
, lua_Debug
*ar
) {
432 elapsed
= (ustime()/1000) - server
.lua_time_start
;
433 if (elapsed
>= server
.lua_time_limit
&& server
.lua_timedout
== 0) {
434 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
);
435 server
.lua_timedout
= 1;
436 /* Once the script timeouts we reenter the event loop to permit others
437 * to call SCRIPT KILL or SHUTDOWN NOSAVE if needed. For this reason
438 * we need to mask the client executing the script from the event loop.
439 * If we don't do that the client may disconnect and could no longer be
440 * here when the EVAL command will return. */
441 aeDeleteFileEvent(server
.el
, server
.lua_caller
->fd
, AE_READABLE
);
443 if (server
.lua_timedout
)
444 aeProcessEvents(server
.el
, AE_FILE_EVENTS
|AE_DONT_WAIT
);
445 if (server
.lua_kill
) {
446 redisLog(REDIS_WARNING
,"Lua script killed by user with SCRIPT KILL.");
447 lua_pushstring(lua
,"Script killed by user with SCRIPT KILL...");
452 void luaLoadLib(lua_State
*lua
, const char *libname
, lua_CFunction luafunc
) {
453 lua_pushcfunction(lua
, luafunc
);
454 lua_pushstring(lua
, libname
);
458 LUALIB_API
int (luaopen_cjson
) (lua_State
*L
);
459 LUALIB_API
int (luaopen_struct
) (lua_State
*L
);
460 LUALIB_API
int (luaopen_cmsgpack
) (lua_State
*L
);
462 void luaLoadLibraries(lua_State
*lua
) {
463 luaLoadLib(lua
, "", luaopen_base
);
464 luaLoadLib(lua
, LUA_TABLIBNAME
, luaopen_table
);
465 luaLoadLib(lua
, LUA_STRLIBNAME
, luaopen_string
);
466 luaLoadLib(lua
, LUA_MATHLIBNAME
, luaopen_math
);
467 luaLoadLib(lua
, LUA_DBLIBNAME
, luaopen_debug
);
468 luaLoadLib(lua
, "cjson", luaopen_cjson
);
469 luaLoadLib(lua
, "struct", luaopen_struct
);
470 luaLoadLib(lua
, "cmsgpack", luaopen_cmsgpack
);
472 #if 0 /* Stuff that we don't load currently, for sandboxing concerns. */
473 luaLoadLib(lua
, LUA_LOADLIBNAME
, luaopen_package
);
474 luaLoadLib(lua
, LUA_OSLIBNAME
, luaopen_os
);
478 /* Remove a functions that we don't want to expose to the Redis scripting
480 void luaRemoveUnsupportedFunctions(lua_State
*lua
) {
482 lua_setglobal(lua
,"loadfile");
485 /* This function installs metamethods in the global table _G that prevent
486 * the creation of globals accidentally.
488 * It should be the last to be called in the scripting engine initialization
489 * sequence, because it may interact with creation of globals. */
490 void scriptingEnableGlobalsProtection(lua_State
*lua
) {
492 sds code
= sdsempty();
495 /* strict.lua from: http://metalua.luaforge.net/src/lib/strict.lua.html.
496 * Modified to be adapted to Redis. */
497 s
[j
++]="local mt = {}\n";
498 s
[j
++]="setmetatable(_G, mt)\n";
499 s
[j
++]="mt.__newindex = function (t, n, v)\n";
500 s
[j
++]=" if debug.getinfo(2) then\n";
501 s
[j
++]=" local w = debug.getinfo(2, \"S\").what\n";
502 s
[j
++]=" if w ~= \"main\" and w ~= \"C\" then\n";
503 s
[j
++]=" error(\"Script attempted to create global variable '\"..tostring(n)..\"'\", 2)\n";
506 s
[j
++]=" rawset(t, n, v)\n";
508 s
[j
++]="mt.__index = function (t, n)\n";
509 s
[j
++]=" if debug.getinfo(2) and debug.getinfo(2, \"S\").what ~= \"C\" then\n";
510 s
[j
++]=" error(\"Script attempted to access unexisting global variable '\"..tostring(n)..\"'\", 2)\n";
512 s
[j
++]=" return rawget(t, n)\n";
516 for (j
= 0; s
[j
] != NULL
; j
++) code
= sdscatlen(code
,s
[j
],strlen(s
[j
]));
517 luaL_loadbuffer(lua
,code
,sdslen(code
),"@enable_strict_lua");
518 lua_pcall(lua
,0,0,0);
522 /* Initialize the scripting environment.
523 * It is possible to call this function to reset the scripting environment
524 * assuming that we call scriptingRelease() before.
525 * See scriptingReset() for more information. */
526 void scriptingInit(void) {
527 lua_State
*lua
= lua_open();
529 luaLoadLibraries(lua
);
530 luaRemoveUnsupportedFunctions(lua
);
532 /* Initialize a dictionary we use to map SHAs to scripts.
533 * This is useful for replication, as we need to replicate EVALSHA
534 * as EVAL, so we need to remember the associated script. */
535 server
.lua_scripts
= dictCreate(&shaScriptObjectDictType
,NULL
);
537 /* Register the redis commands table and fields */
541 lua_pushstring(lua
,"call");
542 lua_pushcfunction(lua
,luaRedisCallCommand
);
543 lua_settable(lua
,-3);
546 lua_pushstring(lua
,"pcall");
547 lua_pushcfunction(lua
,luaRedisPCallCommand
);
548 lua_settable(lua
,-3);
550 /* redis.log and log levels. */
551 lua_pushstring(lua
,"log");
552 lua_pushcfunction(lua
,luaLogCommand
);
553 lua_settable(lua
,-3);
555 lua_pushstring(lua
,"LOG_DEBUG");
556 lua_pushnumber(lua
,REDIS_DEBUG
);
557 lua_settable(lua
,-3);
559 lua_pushstring(lua
,"LOG_VERBOSE");
560 lua_pushnumber(lua
,REDIS_VERBOSE
);
561 lua_settable(lua
,-3);
563 lua_pushstring(lua
,"LOG_NOTICE");
564 lua_pushnumber(lua
,REDIS_NOTICE
);
565 lua_settable(lua
,-3);
567 lua_pushstring(lua
,"LOG_WARNING");
568 lua_pushnumber(lua
,REDIS_WARNING
);
569 lua_settable(lua
,-3);
572 lua_pushstring(lua
, "sha1hex");
573 lua_pushcfunction(lua
, luaRedisSha1hexCommand
);
574 lua_settable(lua
, -3);
576 /* redis.error_reply and redis.status_reply */
577 lua_pushstring(lua
, "error_reply");
578 lua_pushcfunction(lua
, luaRedisErrorReplyCommand
);
579 lua_settable(lua
, -3);
580 lua_pushstring(lua
, "status_reply");
581 lua_pushcfunction(lua
, luaRedisStatusReplyCommand
);
582 lua_settable(lua
, -3);
584 /* Finally set the table as 'redis' global var. */
585 lua_setglobal(lua
,"redis");
587 /* Replace math.random and math.randomseed with our implementations. */
588 lua_getglobal(lua
,"math");
590 lua_pushstring(lua
,"random");
591 lua_pushcfunction(lua
,redis_math_random
);
592 lua_settable(lua
,-3);
594 lua_pushstring(lua
,"randomseed");
595 lua_pushcfunction(lua
,redis_math_randomseed
);
596 lua_settable(lua
,-3);
598 lua_setglobal(lua
,"math");
600 /* Add a helper funciton that we use to sort the multi bulk output of non
601 * deterministic commands, when containing 'false' elements. */
603 char *compare_func
= "function __redis__compare_helper(a,b)\n"
604 " if a == false then a = '' end\n"
605 " if b == false then b = '' end\n"
608 luaL_loadbuffer(lua
,compare_func
,strlen(compare_func
),"@cmp_func_def");
609 lua_pcall(lua
,0,0,0);
612 /* Create the (non connected) client that we use to execute Redis commands
613 * inside the Lua interpreter.
614 * Note: there is no need to create it again when this function is called
615 * by scriptingReset(). */
616 if (server
.lua_client
== NULL
) {
617 server
.lua_client
= createClient(-1);
618 server
.lua_client
->flags
|= REDIS_LUA_CLIENT
;
621 /* Lua beginners ofter don't use "local", this is likely to introduce
622 * subtle bugs in their code. To prevent problems we protect accesses
623 * to global variables. */
624 scriptingEnableGlobalsProtection(lua
);
629 /* Release resources related to Lua scripting.
630 * This function is used in order to reset the scripting environment. */
631 void scriptingRelease(void) {
632 dictRelease(server
.lua_scripts
);
633 lua_close(server
.lua
);
636 void scriptingReset(void) {
641 /* Perform the SHA1 of the input string. We use this both for hasing script
642 * bodies in order to obtain the Lua function name, and in the implementation
645 * 'digest' should point to a 41 bytes buffer: 40 for SHA1 converted into an
646 * hexadecimal number, plus 1 byte for null term. */
647 void sha1hex(char *digest
, char *script
, size_t len
) {
649 unsigned char hash
[20];
650 char *cset
= "0123456789abcdef";
654 SHA1Update(&ctx
,(unsigned char*)script
,len
);
655 SHA1Final(hash
,&ctx
);
657 for (j
= 0; j
< 20; j
++) {
658 digest
[j
*2] = cset
[((hash
[j
]&0xF0)>>4)];
659 digest
[j
*2+1] = cset
[(hash
[j
]&0xF)];
664 void luaReplyToRedisReply(redisClient
*c
, lua_State
*lua
) {
665 int t
= lua_type(lua
,-1);
669 addReplyBulkCBuffer(c
,(char*)lua_tostring(lua
,-1),lua_strlen(lua
,-1));
672 addReply(c
,lua_toboolean(lua
,-1) ? shared
.cone
: shared
.nullbulk
);
675 addReplyLongLong(c
,(long long)lua_tonumber(lua
,-1));
678 /* We need to check if it is an array, an error, or a status reply.
679 * Error are returned as a single element table with 'err' field.
680 * Status replies are returned as single elment table with 'ok' field */
681 lua_pushstring(lua
,"err");
682 lua_gettable(lua
,-2);
683 t
= lua_type(lua
,-1);
684 if (t
== LUA_TSTRING
) {
685 sds err
= sdsnew(lua_tostring(lua
,-1));
686 sdsmapchars(err
,"\r\n"," ",2);
687 addReplySds(c
,sdscatprintf(sdsempty(),"-%s\r\n",err
));
694 lua_pushstring(lua
,"ok");
695 lua_gettable(lua
,-2);
696 t
= lua_type(lua
,-1);
697 if (t
== LUA_TSTRING
) {
698 sds ok
= sdsnew(lua_tostring(lua
,-1));
699 sdsmapchars(ok
,"\r\n"," ",2);
700 addReplySds(c
,sdscatprintf(sdsempty(),"+%s\r\n",ok
));
704 void *replylen
= addDeferredMultiBulkLength(c
);
705 int j
= 1, mbulklen
= 0;
707 lua_pop(lua
,1); /* Discard the 'ok' field value we popped */
709 lua_pushnumber(lua
,j
++);
710 lua_gettable(lua
,-2);
711 t
= lua_type(lua
,-1);
716 luaReplyToRedisReply(c
, lua
);
719 setDeferredMultiBulkLength(c
,replylen
,mbulklen
);
723 addReply(c
,shared
.nullbulk
);
728 /* Set an array of Redis String Objects as a Lua array (table) stored into a
729 * global variable. */
730 void luaSetGlobalArray(lua_State
*lua
, char *var
, robj
**elev
, int elec
) {
734 for (j
= 0; j
< elec
; j
++) {
735 lua_pushlstring(lua
,(char*)elev
[j
]->ptr
,sdslen(elev
[j
]->ptr
));
736 lua_rawseti(lua
,-2,j
+1);
738 lua_setglobal(lua
,var
);
741 /* Define a lua function with the specified function name and body.
742 * The function name musts be a 2 characters long string, since all the
743 * functions we defined in the Lua context are in the form:
747 * On success REDIS_OK is returned, and nothing is left on the Lua stack.
748 * On error REDIS_ERR is returned and an appropriate error is set in the
750 int luaCreateFunction(redisClient
*c
, lua_State
*lua
, char *funcname
, robj
*body
) {
751 sds funcdef
= sdsempty();
753 funcdef
= sdscat(funcdef
,"function ");
754 funcdef
= sdscatlen(funcdef
,funcname
,42);
755 funcdef
= sdscatlen(funcdef
,"() ",3);
756 funcdef
= sdscatlen(funcdef
,body
->ptr
,sdslen(body
->ptr
));
757 funcdef
= sdscatlen(funcdef
," end",4);
759 if (luaL_loadbuffer(lua
,funcdef
,sdslen(funcdef
),"@user_script")) {
760 addReplyErrorFormat(c
,"Error compiling script (new function): %s\n",
761 lua_tostring(lua
,-1));
767 if (lua_pcall(lua
,0,0,0)) {
768 addReplyErrorFormat(c
,"Error running script (new function): %s\n",
769 lua_tostring(lua
,-1));
774 /* We also save a SHA1 -> Original script map in a dictionary
775 * so that we can replicate / write in the AOF all the
776 * EVALSHA commands as EVAL using the original script. */
778 int retval
= dictAdd(server
.lua_scripts
,
779 sdsnewlen(funcname
+2,40),body
);
780 redisAssertWithInfo(c
,NULL
,retval
== DICT_OK
);
786 void evalGenericCommand(redisClient
*c
, int evalsha
) {
787 lua_State
*lua
= server
.lua
;
792 /* We want the same PRNG sequence at every call so that our PRNG is
793 * not affected by external state. */
796 /* We set this flag to zero to remember that so far no random command
797 * was called. This way we can allow the user to call commands like
798 * SRANDMEMBER or RANDOMKEY from Lua scripts as far as no write command
799 * is called (otherwise the replication and AOF would end with non
800 * deterministic sequences).
802 * Thanks to this flag we'll raise an error every time a write command
803 * is called after a random command was used. */
804 server
.lua_random_dirty
= 0;
805 server
.lua_write_dirty
= 0;
807 /* Get the number of arguments that are keys */
808 if (getLongLongFromObjectOrReply(c
,c
->argv
[2],&numkeys
,NULL
) != REDIS_OK
)
810 if (numkeys
> (c
->argc
- 3)) {
811 addReplyError(c
,"Number of keys can't be greater than number of args");
815 /* We obtain the script SHA1, then check if this function is already
816 * defined into the Lua state */
820 /* Hash the code if this is an EVAL call */
821 sha1hex(funcname
+2,c
->argv
[1]->ptr
,sdslen(c
->argv
[1]->ptr
));
823 /* We already have the SHA if it is a EVALSHA */
825 char *sha
= c
->argv
[1]->ptr
;
827 for (j
= 0; j
< 40; j
++)
828 funcname
[j
+2] = tolower(sha
[j
]);
832 /* Try to lookup the Lua function */
833 lua_getglobal(lua
, funcname
);
834 if (lua_isnil(lua
,1)) {
835 lua_pop(lua
,1); /* remove the nil from the stack */
836 /* Function not defined... let's define it if we have the
837 * body of the funciton. If this is an EVALSHA call we can just
838 * return an error. */
840 addReply(c
, shared
.noscripterr
);
843 if (luaCreateFunction(c
,lua
,funcname
,c
->argv
[1]) == REDIS_ERR
) return;
844 /* Now the following is guaranteed to return non nil */
845 lua_getglobal(lua
, funcname
);
846 redisAssert(!lua_isnil(lua
,1));
849 /* Populate the argv and keys table accordingly to the arguments that
851 luaSetGlobalArray(lua
,"KEYS",c
->argv
+3,numkeys
);
852 luaSetGlobalArray(lua
,"ARGV",c
->argv
+3+numkeys
,c
->argc
-3-numkeys
);
854 /* Select the right DB in the context of the Lua client */
855 selectDb(server
.lua_client
,c
->db
->id
);
857 /* Set an hook in order to be able to stop the script execution if it
858 * is running for too much time.
859 * We set the hook only if the time limit is enabled as the hook will
860 * make the Lua script execution slower. */
861 server
.lua_caller
= c
;
862 server
.lua_time_start
= ustime()/1000;
864 if (server
.lua_time_limit
> 0 && server
.masterhost
== NULL
) {
865 lua_sethook(lua
,luaMaskCountHook
,LUA_MASKCOUNT
,100000);
869 /* At this point whatever this script was never seen before or if it was
870 * already defined, we can call it. We have zero arguments and expect
871 * a single return value. */
872 if (lua_pcall(lua
,0,1,0)) {
873 if (delhook
) lua_sethook(lua
,luaMaskCountHook
,0,0); /* Disable hook */
874 if (server
.lua_timedout
) {
875 server
.lua_timedout
= 0;
876 /* Restore the readable handler that was unregistered when the
877 * script timeout was detected. */
878 aeCreateFileEvent(server
.el
,c
->fd
,AE_READABLE
,
879 readQueryFromClient
,c
);
881 server
.lua_caller
= NULL
;
882 selectDb(c
,server
.lua_client
->db
->id
); /* set DB ID from Lua client */
883 addReplyErrorFormat(c
,"Error running script (call to %s): %s\n",
884 funcname
, lua_tostring(lua
,-1));
886 lua_gc(lua
,LUA_GCCOLLECT
,0);
889 if (delhook
) lua_sethook(lua
,luaMaskCountHook
,0,0); /* Disable hook */
890 server
.lua_timedout
= 0;
891 server
.lua_caller
= NULL
;
892 selectDb(c
,server
.lua_client
->db
->id
); /* set DB ID from Lua client */
893 luaReplyToRedisReply(c
,lua
);
894 lua_gc(lua
,LUA_GCSTEP
,1);
896 /* If we have slaves attached we want to replicate this command as
897 * EVAL instead of EVALSHA. We do this also in the AOF as currently there
898 * is no easy way to propagate a command in a different way in the AOF
899 * and in the replication link.
901 * IMPROVEMENT POSSIBLE:
902 * 1) Replicate this command as EVALSHA in the AOF.
903 * 2) Remember what slave already received a given script, and replicate
904 * the EVALSHA against this slaves when possible.
907 robj
*script
= dictFetchValue(server
.lua_scripts
,c
->argv
[1]->ptr
);
909 redisAssertWithInfo(c
,NULL
,script
!= NULL
);
910 rewriteClientCommandArgument(c
,0,
911 resetRefCount(createStringObject("EVAL",4)));
912 rewriteClientCommandArgument(c
,1,script
);
916 void evalCommand(redisClient
*c
) {
917 evalGenericCommand(c
,0);
920 void evalShaCommand(redisClient
*c
) {
921 if (sdslen(c
->argv
[1]->ptr
) != 40) {
922 /* We know that a match is not possible if the provided SHA is
923 * not the right length. So we return an error ASAP, this way
924 * evalGenericCommand() can be implemented without string length
926 addReply(c
, shared
.noscripterr
);
929 evalGenericCommand(c
,1);
932 /* We replace math.random() with our implementation that is not affected
933 * by specific libc random() implementations and will output the same sequence
934 * (for the same seed) in every arch. */
936 /* The following implementation is the one shipped with Lua itself but with
937 * rand() replaced by redisLrand48(). */
938 int redis_math_random (lua_State
*L
) {
939 /* the `%' avoids the (rare) case of r==1, and is needed also because on
940 some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */
941 lua_Number r
= (lua_Number
)(redisLrand48()%REDIS_LRAND
48_MAX
) /
942 (lua_Number
)REDIS_LRAND48_MAX
;
943 switch (lua_gettop(L
)) { /* check number of arguments */
944 case 0: { /* no arguments */
945 lua_pushnumber(L
, r
); /* Number between 0 and 1 */
948 case 1: { /* only upper limit */
949 int u
= luaL_checkint(L
, 1);
950 luaL_argcheck(L
, 1<=u
, 1, "interval is empty");
951 lua_pushnumber(L
, floor(r
*u
)+1); /* int between 1 and `u' */
954 case 2: { /* lower and upper limits */
955 int l
= luaL_checkint(L
, 1);
956 int u
= luaL_checkint(L
, 2);
957 luaL_argcheck(L
, l
<=u
, 2, "interval is empty");
958 lua_pushnumber(L
, floor(r
*(u
-l
+1))+l
); /* int between `l' and `u' */
961 default: return luaL_error(L
, "wrong number of arguments");
966 int redis_math_randomseed (lua_State
*L
) {
967 redisSrand48(luaL_checkint(L
, 1));
971 /* ---------------------------------------------------------------------------
972 * SCRIPT command for script environment introspection and control
973 * ------------------------------------------------------------------------- */
975 void scriptCommand(redisClient
*c
) {
976 if (c
->argc
== 2 && !strcasecmp(c
->argv
[1]->ptr
,"flush")) {
978 addReply(c
,shared
.ok
);
979 server
.dirty
++; /* Replicating this command is a good idea. */
980 } else if (c
->argc
>= 2 && !strcasecmp(c
->argv
[1]->ptr
,"exists")) {
983 addReplyMultiBulkLen(c
, c
->argc
-2);
984 for (j
= 2; j
< c
->argc
; j
++) {
985 if (dictFind(server
.lua_scripts
,c
->argv
[j
]->ptr
))
986 addReply(c
,shared
.cone
);
988 addReply(c
,shared
.czero
);
990 } else if (c
->argc
== 3 && !strcasecmp(c
->argv
[1]->ptr
,"load")) {
996 sha1hex(funcname
+2,c
->argv
[2]->ptr
,sdslen(c
->argv
[2]->ptr
));
997 sha
= sdsnewlen(funcname
+2,40);
998 if (dictFind(server
.lua_scripts
,sha
) == NULL
) {
999 if (luaCreateFunction(c
,server
.lua
,funcname
,c
->argv
[2])
1005 addReplyBulkCBuffer(c
,funcname
+2,40);
1007 } else if (c
->argc
== 2 && !strcasecmp(c
->argv
[1]->ptr
,"kill")) {
1008 if (server
.lua_caller
== NULL
) {
1009 addReplySds(c
,sdsnew("-NOTBUSY No scripts in execution right now.\r\n"));
1010 } else if (server
.lua_write_dirty
) {
1011 addReplySds(c
,sdsnew("-UNKILLABLE 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.\r\n"));
1013 server
.lua_kill
= 1;
1014 addReply(c
,shared
.ok
);
1017 addReplyError(c
, "Unknown SCRIPT subcommand or wrong # of args.");