+
+/* We replace math.random() with our implementation that is not affected
+ * by specific libc random() implementations and will output the same sequence
+ * (for the same seed) in every arch. */
+
+/* The following implementation is the one shipped with Lua itself but with
+ * rand() replaced by redisLrand48(). */
+int redis_math_random (lua_State *L) {
+ /* the `%' avoids the (rare) case of r==1, and is needed also because on
+ some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */
+ lua_Number r = (lua_Number)(redisLrand48()%REDIS_LRAND48_MAX) /
+ (lua_Number)REDIS_LRAND48_MAX;
+ switch (lua_gettop(L)) { /* check number of arguments */
+ case 0: { /* no arguments */
+ lua_pushnumber(L, r); /* Number between 0 and 1 */
+ break;
+ }
+ case 1: { /* only upper limit */
+ int u = luaL_checkint(L, 1);
+ luaL_argcheck(L, 1<=u, 1, "interval is empty");
+ lua_pushnumber(L, floor(r*u)+1); /* int between 1 and `u' */
+ break;
+ }
+ case 2: { /* lower and upper limits */
+ int l = luaL_checkint(L, 1);
+ int u = luaL_checkint(L, 2);
+ luaL_argcheck(L, l<=u, 2, "interval is empty");
+ lua_pushnumber(L, floor(r*(u-l+1))+l); /* int between `l' and `u' */
+ break;
+ }
+ default: return luaL_error(L, "wrong number of arguments");
+ }
+ return 1;
+}
+
+int redis_math_randomseed (lua_State *L) {
+ redisSrand48(luaL_checkint(L, 1));
+ return 0;
+}
+
+/* ---------------------------------------------------------------------------
+ * SCRIPT command for script environment introspection and control
+ * ------------------------------------------------------------------------- */
+
+void scriptCommand(redisClient *c) {
+ if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"flush")) {
+ scriptingReset();
+ addReply(c,shared.ok);
+ server.dirty++; /* Replicating this command is a good idea. */
+ } else if (c->argc >= 2 && !strcasecmp(c->argv[1]->ptr,"exists")) {
+ int j;
+
+ addReplyMultiBulkLen(c, c->argc-2);
+ for (j = 2; j < c->argc; j++) {
+ if (dictFind(server.lua_scripts,c->argv[j]->ptr))
+ addReply(c,shared.cone);
+ else
+ addReply(c,shared.czero);
+ }
+ } else if (c->argc == 3 && !strcasecmp(c->argv[1]->ptr,"load")) {
+ char funcname[43];
+ sds sha;
+
+ funcname[0] = 'f';
+ funcname[1] = '_';
+ sha1hex(funcname+2,c->argv[2]->ptr,sdslen(c->argv[2]->ptr));
+ sha = sdsnewlen(funcname+2,40);
+ if (dictFind(server.lua_scripts,sha) == NULL) {
+ if (luaCreateFunction(c,server.lua,funcname,c->argv[2])
+ == REDIS_ERR) {
+ sdsfree(sha);
+ return;
+ }
+ }
+ addReplyBulkCBuffer(c,funcname+2,40);
+ sdsfree(sha);
+ } else if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"kill")) {
+ if (server.lua_caller == NULL) {
+ addReplySds(c,sdsnew("-NOTBUSY No scripts in execution right now.\r\n"));
+ } else if (server.lua_write_dirty) {
+ 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"));
+ } else {
+ server.lua_kill = 1;
+ addReply(c,shared.ok);
+ }
+ } else {
+ addReplyError(c, "Unknown SCRIPT subcommand or wrong # of args.");
+ }
+}