From 7e11825ef4467ccc64f961761ea050a3df4853ba Mon Sep 17 00:00:00 2001 From: antirez Date: Wed, 5 Sep 2018 15:48:08 +0200 Subject: [PATCH] Safer script stop condition on OOM. Here the idea is that we do not want freeMemoryIfNeeded() to propagate a DEL command before the script and change what happens in the script execution once it reaches the slave. For example see this potential issue (in the words of @soloestoy): On master, we run the following script: if redis.call('get','key') then redis.call('set','xxx','yyy') end redis.call('set','c','d') Then when redis attempts to execute redis.call('set','xxx','yyy'), we call freeMemoryIfNeeded(), and the key may get deleted, and because redis.call('set','xxx','yyy') has already been executed on master, this script will be replicated to slave. But the slave received "DEL key" before the script, and will ignore maxmemory, so after that master has xxx and c, slave has only one key c. Note that this patch (and other related work) was authored collaboratively in issue #5250 with the help of @soloestoy and @oranagra. Related to issue #5250. --- src/scripting.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/scripting.c b/src/scripting.c index 4b5b0002..43f8d09a 100644 --- a/src/scripting.c +++ b/src/scripting.c @@ -512,10 +512,13 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) { * could enlarge the memory usage are not allowed, but only if this is the * first write in the context of this script, otherwise we can't stop * in the middle. */ - if (server.maxmemory && server.lua_write_dirty == 0 && + if (server.maxmemory && /* Maxmemory is actually enabled. */ + !server.loading && /* Don't care about mem if loading. */ + !server.masterhost && /* Slave must execute the script. */ + server.lua_write_dirty == 0 && /* Script had no side effects so far. */ (cmd->flags & CMD_DENYOOM)) { - if (freeMemoryIfNeeded() == C_ERR) { + if (getMaxmemoryState(NULL,NULL,NULL,NULL) != C_OK) { luaPushError(lua, shared.oomerr->ptr); goto cleanup; }