]>
git.saurik.com Git - redis.git/blob - src/scripting.c
11 char * redisProtocolToLuaType_Int ( lua_State
* lua
, char * reply
);
12 char * redisProtocolToLuaType_Bulk ( lua_State
* lua
, char * reply
);
13 char * redisProtocolToLuaType_Status ( lua_State
* lua
, char * reply
);
14 char * redisProtocolToLuaType_Error ( lua_State
* lua
, char * reply
);
15 char * redisProtocolToLuaType_MultiBulk ( lua_State
* lua
, char * reply
);
16 int redis_math_random ( lua_State
* L
);
17 int redis_math_randomseed ( lua_State
* L
);
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.
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.
29 * Note: in this function we do not do any sanity check as the reply is
30 * generated by Redis directly. This allows use to go faster.
31 * The reply string can be altered during the parsing as it is discared
32 * after the conversion is completed.
34 * Errors are returned as a table with a single 'err' field set to the
38 char * redisProtocolToLuaType ( lua_State
* lua
, char * reply
) {
43 p
= redisProtocolToLuaType_Int ( lua
, reply
);
46 p
= redisProtocolToLuaType_Bulk ( lua
, reply
);
49 p
= redisProtocolToLuaType_Status ( lua
, reply
);
52 p
= redisProtocolToLuaType_Error ( lua
, reply
);
55 p
= redisProtocolToLuaType_MultiBulk ( lua
, reply
);
61 char * redisProtocolToLuaType_Int ( lua_State
* lua
, char * reply
) {
62 char * p
= strchr ( reply
+ 1 , ' \r ' );
65 string2ll ( reply
+ 1 , p
- reply
- 1 ,& value
);
66 lua_pushnumber ( lua
,( lua_Number
) value
);
70 char * redisProtocolToLuaType_Bulk ( lua_State
* lua
, char * reply
) {
71 char * p
= strchr ( reply
+ 1 , ' \r ' );
74 string2ll ( reply
+ 1 , p
- reply
- 1 ,& bulklen
);
76 lua_pushboolean ( lua
, 0 );
79 lua_pushlstring ( lua
, p
+ 2 , bulklen
);
84 char * redisProtocolToLuaType_Status ( lua_State
* lua
, char * reply
) {
85 char * p
= strchr ( reply
+ 1 , ' \r ' );
88 lua_pushstring ( lua
, "ok" );
89 lua_pushlstring ( lua
, reply
+ 1 , p
- reply
- 1 );
94 char * redisProtocolToLuaType_Error ( lua_State
* lua
, char * reply
) {
95 char * p
= strchr ( reply
+ 1 , ' \r ' );
98 lua_pushstring ( lua
, "err" );
99 lua_pushlstring ( lua
, reply
+ 1 , p
- reply
- 1 );
100 lua_settable ( lua
,- 3 );
104 char * redisProtocolToLuaType_MultiBulk ( lua_State
* lua
, char * reply
) {
105 char * p
= strchr ( reply
+ 1 , ' \r ' );
109 string2ll ( reply
+ 1 , p
- reply
- 1 ,& mbulklen
);
111 if ( mbulklen
== - 1 ) {
112 lua_pushboolean ( lua
, 0 );
116 for ( j
= 0 ; j
< mbulklen
; j
++) {
117 lua_pushnumber ( lua
, j
+ 1 );
118 p
= redisProtocolToLuaType ( lua
, p
);
119 lua_settable ( lua
,- 3 );
124 void luaPushError ( lua_State
* lua
, char * error
) {
126 lua_pushstring ( lua
, "err" );
127 lua_pushstring ( lua
, error
);
128 lua_settable ( lua
,- 3 );
131 int luaRedisGenericCommand ( lua_State
* lua
, int raise_error
) {
132 int j
, argc
= lua_gettop ( lua
);
133 struct redisCommand
* cmd
;
135 redisClient
* c
= server
. lua_client
;
138 /* Build the arguments vector */
139 argv
= zmalloc ( sizeof ( robj
*)* argc
);
140 for ( j
= 0 ; j
< argc
; j
++) {
141 if (! lua_isstring ( lua
, j
+ 1 )) break ;
142 argv
[ j
] = createStringObject (( char *) lua_tostring ( lua
, j
+ 1 ),
143 lua_strlen ( lua
, j
+ 1 ));
146 /* Check if one of the arguments passed by the Lua script
147 * is not a string or an integer (lua_isstring() return true for
148 * integers as well). */
152 decrRefCount ( argv
[ j
]);
157 "Lua redis() command arguments must be strings or integers" );
161 /* Setup our fake client for command execution */
166 cmd
= lookupCommand ( argv
[ 0 ]-> ptr
);
167 if (! cmd
|| (( cmd
-> arity
> 0 && cmd
-> arity
!= argc
) ||
168 ( argc
< - cmd
-> arity
)))
172 "Wrong number of args calling Redis command From Lua script" );
174 luaPushError ( lua
, "Unknown Redis command called from Lua script" );
178 if ( cmd
-> flags
& REDIS_CMD_NOSCRIPT
) {
179 luaPushError ( lua
, "This Redis command is not allowed from scripts" );
183 if ( cmd
-> flags
& REDIS_CMD_WRITE
&& server
. lua_random_dirty
) {
185 "Write commands not allowed after non deterministic commands" );
189 if ( cmd
-> flags
& REDIS_CMD_RANDOM
) server
. lua_random_dirty
= 1 ;
191 /* Run the command */
194 /* Convert the result of the Redis command into a suitable Lua type.
195 * The first thing we need is to create a single string from the client
199 reply
= sdscatlen ( reply
, c
-> buf
, c
-> bufpos
);
202 while ( listLength ( c
-> reply
)) {
203 robj
* o
= listNodeValue ( listFirst ( c
-> reply
));
205 reply
= sdscatlen ( reply
, o
-> ptr
, sdslen ( o
-> ptr
));
206 listDelNode ( c
-> reply
, listFirst ( c
-> reply
));
208 if ( raise_error
&& reply
[ 0 ] != '-' ) raise_error
= 0 ;
209 redisProtocolToLuaType ( lua
, reply
);
213 /* Clean up. Command code may have changed argv/argc so we use the
214 * argv/argc of the client instead of the local variables. */
215 for ( j
= 0 ; j
< c
-> argc
; j
++)
216 decrRefCount ( c
-> argv
[ j
]);
220 /* If we are here we should have an error in the stack, in the
221 * form of a table with an "err" field. Extract the string to
222 * return the plain error. */
223 lua_pushstring ( lua
, "err" );
224 lua_gettable ( lua
,- 2 );
225 return lua_error ( lua
);
230 int luaRedisCallCommand ( lua_State
* lua
) {
231 return luaRedisGenericCommand ( lua
, 1 );
234 int luaRedisPCallCommand ( lua_State
* lua
) {
235 return luaRedisGenericCommand ( lua
, 0 );
238 int luaLogCommand ( lua_State
* lua
) {
239 int j
, argc
= lua_gettop ( lua
);
244 luaPushError ( lua
, "redis.log() requires two arguments or more." );
246 } else if (! lua_isnumber ( lua
,- argc
)) {
247 luaPushError ( lua
, "First argument must be a number (log level)." );
250 level
= lua_tonumber ( lua
,- argc
);
251 if ( level
< REDIS_DEBUG
|| level
> REDIS_WARNING
) {
252 luaPushError ( lua
, "Invalid debug level." );
256 /* Glue together all the arguments */
258 for ( j
= 1 ; j
< argc
; j
++) {
262 s
= ( char *) lua_tolstring ( lua
,(- argc
)+ j
,& len
);
264 if ( j
!= 1 ) log
= sdscatlen ( log
, " " , 1 );
265 log
= sdscatlen ( log
, s
, len
);
268 redisLogRaw ( level
, log
);
273 void luaMaskCountHook ( lua_State
* lua
, lua_Debug
* ar
) {
278 elapsed
= ( ustime ()/ 1000 ) - server
. lua_time_start
;
279 if ( elapsed
>= server
. lua_time_limit
&& server
. lua_timedout
== 0 ) {
280 redisLog ( REDIS_WARNING
, "Lua slow script detected: still in execution after %l ld milliseconds. You can shut down the server using the SHUTDOWN command." , elapsed
);
281 server
. lua_timedout
= 1 ;
283 if ( server
. lua_timedout
)
284 aeProcessEvents ( server
. el
, AE_FILE_EVENTS
| AE_DONT_WAIT
);
287 void luaLoadLib ( lua_State
* lua
, const char * libname
, lua_CFunction luafunc
) {
288 lua_pushcfunction ( lua
, luafunc
);
289 lua_pushstring ( lua
, libname
);
293 LUALIB_API
int ( luaopen_cjson
) ( lua_State
* L
);
295 void luaLoadLibraries ( lua_State
* lua
) {
296 luaLoadLib ( lua
, "" , luaopen_base
);
297 luaLoadLib ( lua
, LUA_TABLIBNAME
, luaopen_table
);
298 luaLoadLib ( lua
, LUA_STRLIBNAME
, luaopen_string
);
299 luaLoadLib ( lua
, LUA_MATHLIBNAME
, luaopen_math
);
300 luaLoadLib ( lua
, LUA_DBLIBNAME
, luaopen_debug
);
301 luaLoadLib ( lua
, "cjson" , luaopen_cjson
);
303 #if 0 /* Stuff that we don't load currently, for sandboxing concerns. */
304 luaLoadLib ( lua
, LUA_LOADLIBNAME
, luaopen_package
);
305 luaLoadLib ( lua
, LUA_OSLIBNAME
, luaopen_os
);
309 /* Initialize the scripting environment.
310 * It is possible to call this function to reset the scripting environment
311 * assuming that we call scriptingRelease() before.
312 * See scriptingReset() for more information. */
313 void scriptingInit ( void ) {
314 lua_State
* lua
= lua_open ();
315 luaLoadLibraries ( lua
);
317 /* Initialize a dictionary we use to map SHAs to scripts.
318 * This is useful for replication, as we need to replicate EVALSHA
319 * as EVAL, so we need to remember the associated script. */
320 server
. lua_scripts
= dictCreate (& dbDictType
, NULL
);
322 /* Register the redis commands table and fields */
326 lua_pushstring ( lua
, "call" );
327 lua_pushcfunction ( lua
, luaRedisCallCommand
);
328 lua_settable ( lua
,- 3 );
331 lua_pushstring ( lua
, "pcall" );
332 lua_pushcfunction ( lua
, luaRedisPCallCommand
);
333 lua_settable ( lua
,- 3 );
335 /* redis.log and log levels. */
336 lua_pushstring ( lua
, "log" );
337 lua_pushcfunction ( lua
, luaLogCommand
);
338 lua_settable ( lua
,- 3 );
340 lua_pushstring ( lua
, "LOG_DEBUG" );
341 lua_pushnumber ( lua
, REDIS_DEBUG
);
342 lua_settable ( lua
,- 3 );
344 lua_pushstring ( lua
, "LOG_VERBOSE" );
345 lua_pushnumber ( lua
, REDIS_VERBOSE
);
346 lua_settable ( lua
,- 3 );
348 lua_pushstring ( lua
, "LOG_NOTICE" );
349 lua_pushnumber ( lua
, REDIS_NOTICE
);
350 lua_settable ( lua
,- 3 );
352 lua_pushstring ( lua
, "LOG_WARNING" );
353 lua_pushnumber ( lua
, REDIS_WARNING
);
354 lua_settable ( lua
,- 3 );
356 /* Finally set the table as 'redis' global var. */
357 lua_setglobal ( lua
, "redis" );
359 /* Replace math.random and math.randomseed with our implementations. */
360 lua_getglobal ( lua
, "math" );
362 lua_pushstring ( lua
, "random" );
363 lua_pushcfunction ( lua
, redis_math_random
);
364 lua_settable ( lua
,- 3 );
366 lua_pushstring ( lua
, "randomseed" );
367 lua_pushcfunction ( lua
, redis_math_randomseed
);
368 lua_settable ( lua
,- 3 );
370 lua_setglobal ( lua
, "math" );
372 /* Create the (non connected) client that we use to execute Redis commands
373 * inside the Lua interpreter.
374 * Note: there is no need to create it again when this function is called
375 * by scriptingReset(). */
376 if ( server
. lua_client
== NULL
) {
377 server
. lua_client
= createClient (- 1 );
378 server
. lua_client
-> flags
|= REDIS_LUA_CLIENT
;
384 /* Release resources related to Lua scripting.
385 * This function is used in order to reset the scripting environment. */
386 void scriptingRelease ( void ) {
387 dictRelease ( server
. lua_scripts
);
388 lua_close ( server
. lua
);
391 void scriptingReset ( void ) {
396 /* Hash the scripit into a SHA1 digest. We use this as Lua function name.
397 * Digest should point to a 41 bytes buffer: 40 for SHA1 converted into an
398 * hexadecimal number, plus 1 byte for null term. */
399 void hashScript ( char * digest
, char * script
, size_t len
) {
401 unsigned char hash
[ 20 ];
402 char * cset
= "0123456789abcdef" ;
406 SHA1Update (& ctx
,( unsigned char *) script
, len
);
407 SHA1Final ( hash
,& ctx
);
409 for ( j
= 0 ; j
< 20 ; j
++) {
410 digest
[ j
* 2 ] = cset
[(( hash
[ j
]& 0xF0 )>> 4 )];
411 digest
[ j
* 2 + 1 ] = cset
[( hash
[ j
]& 0xF )];
416 void luaReplyToRedisReply ( redisClient
* c
, lua_State
* lua
) {
417 int t
= lua_type ( lua
,- 1 );
421 addReplyBulkCBuffer ( c
,( char *) lua_tostring ( lua
,- 1 ), lua_strlen ( lua
,- 1 ));
424 addReply ( c
, lua_toboolean ( lua
,- 1 ) ? shared
. cone
: shared
. nullbulk
);
427 addReplyLongLong ( c
,( long long ) lua_tonumber ( lua
,- 1 ));
430 /* We need to check if it is an array, an error, or a status reply.
431 * Error are returned as a single element table with 'err' field.
432 * Status replies are returned as single elment table with 'ok' field */
433 lua_pushstring ( lua
, "err" );
434 lua_gettable ( lua
,- 2 );
435 t
= lua_type ( lua
,- 1 );
436 if ( t
== LUA_TSTRING
) {
437 sds err
= sdsnew ( lua_tostring ( lua
,- 1 ));
438 sdsmapchars ( err
, " \r\n " , " " , 2 );
439 addReplySds ( c
, sdscatprintf ( sdsempty (), "- %s \r\n " , err
));
446 lua_pushstring ( lua
, "ok" );
447 lua_gettable ( lua
,- 2 );
448 t
= lua_type ( lua
,- 1 );
449 if ( t
== LUA_TSTRING
) {
450 sds ok
= sdsnew ( lua_tostring ( lua
,- 1 ));
451 sdsmapchars ( ok
, " \r\n " , " " , 2 );
452 addReplySds ( c
, sdscatprintf ( sdsempty (), "+ %s \r\n " , ok
));
456 void * replylen
= addDeferredMultiBulkLength ( c
);
457 int j
= 1 , mbulklen
= 0 ;
459 lua_pop ( lua
, 1 ); /* Discard the 'ok' field value we popped */
461 lua_pushnumber ( lua
, j
++);
462 lua_gettable ( lua
,- 2 );
463 t
= lua_type ( lua
,- 1 );
468 luaReplyToRedisReply ( c
, lua
);
471 setDeferredMultiBulkLength ( c
, replylen
, mbulklen
);
475 addReply ( c
, shared
. nullbulk
);
480 /* Set an array of Redis String Objects as a Lua array (table) stored into a
481 * global variable. */
482 void luaSetGlobalArray ( lua_State
* lua
, char * var
, robj
** elev
, int elec
) {
486 for ( j
= 0 ; j
< elec
; j
++) {
487 lua_pushlstring ( lua
,( char *) elev
[ j
]-> ptr
, sdslen ( elev
[ j
]-> ptr
));
488 lua_rawseti ( lua
,- 2 , j
+ 1 );
490 lua_setglobal ( lua
, var
);
493 /* Define a lua function with the specified function name and body.
494 * The function name musts be a 2 characters long string, since all the
495 * functions we defined in the Lua context are in the form:
499 * On success REDIS_OK is returned, and nothing is left on the Lua stack.
500 * On error REDIS_ERR is returned and an appropriate error is set in the
502 int luaCreateFunction ( redisClient
* c
, lua_State
* lua
, char * funcname
, robj
* body
) {
503 sds funcdef
= sdsempty ();
505 funcdef
= sdscat ( funcdef
, "function " );
506 funcdef
= sdscatlen ( funcdef
, funcname
, 42 );
507 funcdef
= sdscatlen ( funcdef
, " () \n " , 4 );
508 funcdef
= sdscatlen ( funcdef
, body
-> ptr
, sdslen ( body
-> ptr
));
509 funcdef
= sdscatlen ( funcdef
, " \n end \n " , 5 );
511 if ( luaL_loadbuffer ( lua
, funcdef
, sdslen ( funcdef
), "func definition" )) {
512 addReplyErrorFormat ( c
, "Error compiling script (new function): %s \n " ,
513 lua_tostring ( lua
,- 1 ));
519 if ( lua_pcall ( lua
, 0 , 0 , 0 )) {
520 addReplyErrorFormat ( c
, "Error running script (new function): %s \n " ,
521 lua_tostring ( lua
,- 1 ));
526 /* We also save a SHA1 -> Original script map in a dictionary
527 * so that we can replicate / write in the AOF all the
528 * EVALSHA commands as EVAL using the original script. */
530 int retval
= dictAdd ( server
. lua_scripts
,
531 sdsnewlen ( funcname
+ 2 , 40 ), body
);
532 redisAssertWithInfo ( c
, NULL
, retval
== DICT_OK
);
538 void evalGenericCommand ( redisClient
* c
, int evalsha
) {
539 lua_State
* lua
= server
. lua
;
543 /* We want the same PRNG sequence at every call so that our PRNG is
544 * not affected by external state. */
547 /* We set this flag to zero to remember that so far no random command
548 * was called. This way we can allow the user to call commands like
549 * SRANDMEMBER or RANDOMKEY from Lua scripts as far as no write command
550 * is called (otherwise the replication and AOF would end with non
551 * deterministic sequences).
553 * Thanks to this flag we'll raise an error every time a write command
554 * is called after a random command was used. */
555 server
. lua_random_dirty
= 0 ;
557 /* Get the number of arguments that are keys */
558 if ( getLongLongFromObjectOrReply ( c
, c
-> argv
[ 2 ],& numkeys
, NULL
) != REDIS_OK
)
560 if ( numkeys
> ( c
-> argc
- 3 )) {
561 addReplyError ( c
, "Number of keys can't be greater than number of args" );
565 /* We obtain the script SHA1, then check if this function is already
566 * defined into the Lua state */
570 /* Hash the code if this is an EVAL call */
571 hashScript ( funcname
+ 2 , c
-> argv
[ 1 ]-> ptr
, sdslen ( c
-> argv
[ 1 ]-> ptr
));
573 /* We already have the SHA if it is a EVALSHA */
575 char * sha
= c
-> argv
[ 1 ]-> ptr
;
577 for ( j
= 0 ; j
< 40 ; j
++)
578 funcname
[ j
+ 2 ] = tolower ( sha
[ j
]);
582 /* Try to lookup the Lua function */
583 lua_getglobal ( lua
, funcname
);
584 if ( lua_isnil ( lua
, 1 )) {
585 lua_pop ( lua
, 1 ); /* remove the nil from the stack */
586 /* Function not defined... let's define it if we have the
587 * body of the funciton. If this is an EVALSHA call we can just
588 * return an error. */
590 addReply ( c
, shared
. noscripterr
);
593 if ( luaCreateFunction ( c
, lua
, funcname
, c
-> argv
[ 1 ]) == REDIS_ERR
) return ;
594 /* Now the following is guaranteed to return non nil */
595 lua_getglobal ( lua
, funcname
);
596 redisAssert (! lua_isnil ( lua
, 1 ));
599 /* Populate the argv and keys table accordingly to the arguments that
601 luaSetGlobalArray ( lua
, "KEYS" , c
-> argv
+ 3 , numkeys
);
602 luaSetGlobalArray ( lua
, "ARGV" , c
-> argv
+ 3 + numkeys
, c
-> argc
- 3 - numkeys
);
604 /* Select the right DB in the context of the Lua client */
605 selectDb ( server
. lua_client
, c
-> db
-> id
);
607 /* Set an hook in order to be able to stop the script execution if it
608 * is running for too much time.
609 * We set the hook only if the time limit is enabled as the hook will
610 * make the Lua script execution slower. */
611 if ( server
. lua_time_limit
> 0 && server
. masterhost
== NULL
) {
612 lua_sethook ( lua
, luaMaskCountHook
, LUA_MASKCOUNT
, 100000 );
613 server
. lua_time_start
= ustime ()/ 1000 ;
615 lua_sethook ( lua
, luaMaskCountHook
, 0 , 0 );
618 /* At this point whatever this script was never seen before or if it was
619 * already defined, we can call it. We have zero arguments and expect
620 * a single return value. */
621 if ( lua_pcall ( lua
, 0 , 1 , 0 )) {
622 server
. lua_timedout
= 0 ;
623 selectDb ( c
, server
. lua_client
-> db
-> id
); /* set DB ID from Lua client */
624 addReplyErrorFormat ( c
, "Error running script (call to %s ): %s \n " ,
625 funcname
, lua_tostring ( lua
,- 1 ));
627 lua_gc ( lua
, LUA_GCCOLLECT
, 0 );
630 server
. lua_timedout
= 0 ;
631 selectDb ( c
, server
. lua_client
-> db
-> id
); /* set DB ID from Lua client */
632 luaReplyToRedisReply ( c
, lua
);
633 lua_gc ( lua
, LUA_GCSTEP
, 1 );
635 /* If we have slaves attached we want to replicate this command as
636 * EVAL instead of EVALSHA. We do this also in the AOF as currently there
637 * is no easy way to propagate a command in a different way in the AOF
638 * and in the replication link.
640 * IMPROVEMENT POSSIBLE:
641 * 1) Replicate this command as EVALSHA in the AOF.
642 * 2) Remember what slave already received a given script, and replicate
643 * the EVALSHA against this slaves when possible.
646 robj
* script
= dictFetchValue ( server
. lua_scripts
, c
-> argv
[ 1 ]-> ptr
);
648 redisAssertWithInfo ( c
, NULL
, script
!= NULL
);
649 rewriteClientCommandArgument ( c
, 0 ,
650 resetRefCount ( createStringObject ( "EVAL" , 4 )));
651 rewriteClientCommandArgument ( c
, 1 , script
);
655 void evalCommand ( redisClient
* c
) {
656 evalGenericCommand ( c
, 0 );
659 void evalShaCommand ( redisClient
* c
) {
660 if ( sdslen ( c
-> argv
[ 1 ]-> ptr
) != 40 ) {
661 /* We know that a match is not possible if the provided SHA is
662 * not the right length. So we return an error ASAP, this way
663 * evalGenericCommand() can be implemented without string length
665 addReply ( c
, shared
. noscripterr
);
668 evalGenericCommand ( c
, 1 );
671 /* We replace math.random() with our implementation that is not affected
672 * by specific libc random() implementations and will output the same sequence
673 * (for the same seed) in every arch. */
675 /* The following implementation is the one shipped with Lua itself but with
676 * rand() replaced by redisLrand48(). */
677 int redis_math_random ( lua_State
* L
) {
678 /* the `%' avoids the (rare) case of r==1, and is needed also because on
679 some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */
680 lua_Number r
= ( lua_Number
)( redisLrand48 () %REDIS_LRAND
48 _MAX
) /
681 ( lua_Number
) REDIS_LRAND48_MAX
;
682 switch ( lua_gettop ( L
)) { /* check number of arguments */
683 case 0 : { /* no arguments */
684 lua_pushnumber ( L
, r
); /* Number between 0 and 1 */
687 case 1 : { /* only upper limit */
688 int u
= luaL_checkint ( L
, 1 );
689 luaL_argcheck ( L
, 1 <= u
, 1 , "interval is empty" );
690 lua_pushnumber ( L
, floor ( r
* u
)+ 1 ); /* int between 1 and `u' */
693 case 2 : { /* lower and upper limits */
694 int l
= luaL_checkint ( L
, 1 );
695 int u
= luaL_checkint ( L
, 2 );
696 luaL_argcheck ( L
, l
<= u
, 2 , "interval is empty" );
697 lua_pushnumber ( L
, floor ( r
*( u
- l
+ 1 ))+ l
); /* int between `l' and `u' */
700 default : return luaL_error ( L
, "wrong number of arguments" );
705 int redis_math_randomseed ( lua_State
* L
) {
706 redisSrand48 ( luaL_checkint ( L
, 1 ));
710 /* ---------------------------------------------------------------------------
711 * SCRIPT command for script environment introspection and control
712 * ------------------------------------------------------------------------- */
714 void scriptCommand ( redisClient
* c
) {
715 if ( c
-> argc
== 2 && ! strcasecmp ( c
-> argv
[ 1 ]-> ptr
, "flush" )) {
717 addReply ( c
, shared
. ok
);
718 server
. dirty
++; /* Replicating this command is a good idea. */
719 } else if ( c
-> argc
>= 2 && ! strcasecmp ( c
-> argv
[ 1 ]-> ptr
, "exists" )) {
722 addReplyMultiBulkLen ( c
, c
-> argc
- 2 );
723 for ( j
= 2 ; j
< c
-> argc
; j
++) {
724 if ( dictFind ( server
. lua_scripts
, c
-> argv
[ j
]-> ptr
))
725 addReply ( c
, shared
. cone
);
727 addReply ( c
, shared
. czero
);
729 } else if ( c
-> argc
== 3 && ! strcasecmp ( c
-> argv
[ 1 ]-> ptr
, "load" )) {
735 hashScript ( funcname
+ 2 , c
-> argv
[ 2 ]-> ptr
, sdslen ( c
-> argv
[ 2 ]-> ptr
));
736 sha
= sdsnewlen ( funcname
+ 2 , 40 );
737 if ( dictFind ( server
. lua_scripts
, sha
) == NULL
) {
738 if ( luaCreateFunction ( c
, server
. lua
, funcname
, c
-> argv
[ 2 ])
744 addReplyBulkCBuffer ( c
, funcname
+ 2 , 40 );
747 addReplyError ( c
, "Unknown SCRIPT subcommand or wrong # of args." );