From 96e0fe6232afabff501bc72d3978a157ead7f359 Mon Sep 17 00:00:00 2001 From: antirez Date: Thu, 12 Jun 2014 15:51:55 +0200 Subject: [PATCH] Fix semantics of Lua calls to SELECT. Lua scripts are executed in the context of the currently selected database (as selected by the caller of the script). However Lua scripts are also free to use the SELECT command in order to affect other DBs. When SELECT is called frm Lua, the old behavior, before this commit, was to automatically set the Lua caller selected DB to the last DB selected by Lua. See for example the following sequence of commands: SELECT 0 SET x 10 EVAL "redis.call('select','1')" 0 SET x 20 Before this commit after the execution of this sequence of commands, we'll have x=10 in DB 0, and x=20 in DB 1. Because of the problem above, there was a bug affecting replication of Lua scripts, because of the actual implementation of replication. It was possible to fix the implementation of Lua scripts in order to fix the issue, but looking closely, the bug is the consequence of the behavior of Lua ability to set the caller's DB. Under the old semantics, a script selecting a different DB, has no simple ways to restore the state and select back the previously selected DB. Moreover the script auhtor must remember that the restore is needed, otherwise the new commands executed by the caller, will be executed in the context of a different DB. So this commit fixes both the replication issue, and this hard-to-use semantics, by removing the ability of Lua, after the script execution, to force the caller to switch to the DB selected by the Lua script. The new behavior of the previous sequence of commadns is to just set X=20 in DB 0. However Lua scripts are still capable of writing / reading from different DBs if needed. WARNING: This is a semantical change that will break programs that are conceived to select the client selected DB via Lua scripts. This fixes issue #1811. --- src/scripting.c | 1 - tests/unit/scripting.tcl | 12 ++++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/scripting.c b/src/scripting.c index c968adb06..ef00eede6 100644 --- a/src/scripting.c +++ b/src/scripting.c @@ -994,7 +994,6 @@ void evalGenericCommand(redisClient *c, int evalsha) { readQueryFromClient,c); } server.lua_caller = NULL; - selectDb(c,server.lua_client->db->id); /* set DB ID from Lua client */ /* Call the Lua garbage collector from time to time to avoid a * full cycle performed by Lua, which adds too latency. diff --git a/tests/unit/scripting.tcl b/tests/unit/scripting.tcl index 2c4171aeb..760280e4e 100644 --- a/tests/unit/scripting.tcl +++ b/tests/unit/scripting.tcl @@ -110,17 +110,21 @@ start_server {tags {"scripting"}} { } 0 } {boolean 1} - test {EVAL - Is Lua affecting the currently selected DB?} { + test {EVAL - Is the Lua client using the currently selected DB?} { r set mykey "this is DB 9" r select 10 r set mykey "this is DB 10" r eval {return redis.pcall('get','mykey')} 0 } {this is DB 10} - test {EVAL - Is Lua seleced DB retained?} { + test {EVAL - SELECT inside Lua should not affect the caller} { + # here we DB 10 is selected + r set mykey "original value" r eval {return redis.pcall('select','9')} 0 - r get mykey - } {this is DB 9} + set res [r get mykey] + r select 9 + set res + } {original value} if 0 { test {EVAL - Script can't run more than configured time limit} { -- GitLab