From 9f772cc23744804fc4b5da2aa7985c4c512abf55 Mon Sep 17 00:00:00 2001 From: antirez Date: Tue, 27 Sep 2011 15:30:31 +0200 Subject: [PATCH] Return errors if a write command is called inside a Lua script after a random command was called. See https://github.com/antirez/redis/issues/95 for more information. --- src/redis.h | 2 ++ src/scripting.c | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/redis.h b/src/redis.h index 032602641..ec982ee93 100644 --- a/src/redis.h +++ b/src/redis.h @@ -623,6 +623,8 @@ struct redisServer { dict *lua_scripts; /* A dictionary of SHA1 -> Lua scripts */ long long lua_time_limit; long long lua_time_start; + int lua_random_dirty; /* True if a random command was called during the + exection of the current script. */ }; typedef struct pubsubPattern { diff --git a/src/scripting.c b/src/scripting.c index 0c18d9165..f62e5c293 100644 --- a/src/scripting.c +++ b/src/scripting.c @@ -180,6 +180,14 @@ int luaRedisCommand(lua_State *lua) { goto cleanup; } + if (cmd->flags & REDIS_CMD_WRITE && server.lua_random_dirty) { + luaPushError(lua, + "Write commands not allowed after non deterministic commands"); + goto cleanup; + } + + if (cmd->flags & REDIS_CMD_RANDOM) server.lua_random_dirty = 1; + /* Run the command */ cmd->proc(c); @@ -425,6 +433,16 @@ void evalGenericCommand(redisClient *c, int evalsha) { * not affected by external state. */ redisSrand48(0); + /* We set this flag to zero to remember that so far no random command + * was called. This way we can allow the user to call commands like + * SRANDMEMBER or RANDOMKEY from Lua scripts as far as no write command + * is called (otherwise the replication and AOF would end with non + * deterministic sequences). + * + * Thanks to this flag we'll raise an error every time a write command + * is called after a random command was used. */ + server.lua_random_dirty = 0; + /* Get the number of arguments that are keys */ if (getLongLongFromObjectOrReply(c,c->argv[2],&numkeys,NULL) != REDIS_OK) return;