2021-10-07 07:41:26 -04:00
|
|
|
start_server {tags {"scripting"}} {
|
|
|
|
test {FUNCTION - Basic usage} {
|
|
|
|
r function create LUA test {return 'hello'}
|
|
|
|
r fcall test 0
|
|
|
|
} {hello}
|
|
|
|
|
|
|
|
test {FUNCTION - Create an already exiting function raise error} {
|
|
|
|
catch {
|
|
|
|
r function create LUA test {return 'hello1'}
|
|
|
|
} e
|
|
|
|
set _ $e
|
|
|
|
} {*Function already exists*}
|
|
|
|
|
2021-12-26 01:37:24 -05:00
|
|
|
test {FUNCTION - Create an already exiting function raise error (case insensitive)} {
|
|
|
|
catch {
|
|
|
|
r function create LUA TEST {return 'hello1'}
|
|
|
|
} e
|
|
|
|
set _ $e
|
|
|
|
} {*Function already exists*}
|
|
|
|
|
|
|
|
test {FUNCTION - Create a function with wrong name format} {
|
|
|
|
catch {
|
|
|
|
r function create LUA {bad\0foramat} {return 'hello1'}
|
|
|
|
} e
|
|
|
|
set _ $e
|
|
|
|
} {*Function names can only contain letters and numbers*}
|
|
|
|
|
2021-10-07 07:41:26 -04:00
|
|
|
test {FUNCTION - Create function with unexisting engine} {
|
|
|
|
catch {
|
|
|
|
r function create bad_engine test {return 'hello1'}
|
|
|
|
} e
|
|
|
|
set _ $e
|
|
|
|
} {*Engine not found*}
|
|
|
|
|
|
|
|
test {FUNCTION - Test uncompiled script} {
|
|
|
|
catch {
|
|
|
|
r function create LUA test1 {bad script}
|
|
|
|
} e
|
|
|
|
set _ $e
|
|
|
|
} {*Error compiling function*}
|
|
|
|
|
|
|
|
test {FUNCTION - test replace argument} {
|
|
|
|
r function create LUA test REPLACE {return 'hello1'}
|
|
|
|
r fcall test 0
|
|
|
|
} {hello1}
|
|
|
|
|
2021-12-26 01:37:24 -05:00
|
|
|
test {FUNCTION - test function case insensitive} {
|
|
|
|
r fcall TEST 0
|
|
|
|
} {hello1}
|
|
|
|
|
2021-10-07 07:41:26 -04:00
|
|
|
test {FUNCTION - test replace argument with function creation failure keeps old function} {
|
|
|
|
catch {r function create LUA test REPLACE {error}}
|
|
|
|
r fcall test 0
|
|
|
|
} {hello1}
|
|
|
|
|
|
|
|
test {FUNCTION - test function delete} {
|
|
|
|
r function delete test
|
|
|
|
catch {
|
|
|
|
r fcall test 0
|
|
|
|
} e
|
|
|
|
set _ $e
|
|
|
|
} {*Function not found*}
|
|
|
|
|
|
|
|
test {FUNCTION - test description argument} {
|
|
|
|
r function create LUA test DESCRIPTION {some description} {return 'hello'}
|
|
|
|
r function list
|
|
|
|
} {{name test engine LUA description {some description}}}
|
|
|
|
|
|
|
|
test {FUNCTION - test info specific function} {
|
|
|
|
r function info test WITHCODE
|
|
|
|
} {name test engine LUA description {some description} code {return 'hello'}}
|
|
|
|
|
|
|
|
test {FUNCTION - test info without code} {
|
|
|
|
r function info test
|
|
|
|
} {name test engine LUA description {some description}}
|
|
|
|
|
|
|
|
test {FUNCTION - test info on function that does not exists} {
|
|
|
|
catch {
|
|
|
|
r function info bad_function_name
|
|
|
|
} e
|
|
|
|
set _ $e
|
|
|
|
} {*Function does not exists*}
|
|
|
|
|
|
|
|
test {FUNCTION - test info with bad number of arguments} {
|
|
|
|
catch {
|
|
|
|
r function info test WITHCODE bad_arg
|
|
|
|
} e
|
|
|
|
set _ $e
|
|
|
|
} {*wrong number of arguments*}
|
|
|
|
|
|
|
|
test {FUNCTION - test fcall bad arguments} {
|
|
|
|
catch {
|
|
|
|
r fcall test bad_arg
|
|
|
|
} e
|
|
|
|
set _ $e
|
|
|
|
} {*Bad number of keys provided*}
|
|
|
|
|
|
|
|
test {FUNCTION - test fcall bad number of keys arguments} {
|
|
|
|
catch {
|
|
|
|
r fcall test 10 key1
|
|
|
|
} e
|
|
|
|
set _ $e
|
|
|
|
} {*Number of keys can't be greater than number of args*}
|
|
|
|
|
|
|
|
test {FUNCTION - test fcall negative number of keys} {
|
|
|
|
catch {
|
|
|
|
r fcall test -1 key1
|
|
|
|
} e
|
|
|
|
set _ $e
|
|
|
|
} {*Number of keys can't be negative*}
|
|
|
|
|
|
|
|
test {FUNCTION - test function delete on not exiting function} {
|
|
|
|
catch {
|
|
|
|
r function delete test1
|
|
|
|
} e
|
|
|
|
set _ $e
|
|
|
|
} {*Function not found*}
|
|
|
|
|
|
|
|
test {FUNCTION - test function kill when function is not running} {
|
|
|
|
catch {
|
|
|
|
r function kill
|
|
|
|
} e
|
|
|
|
set _ $e
|
|
|
|
} {*No scripts in execution*}
|
|
|
|
|
|
|
|
test {FUNCTION - test wrong subcommand} {
|
|
|
|
catch {
|
|
|
|
r function bad_subcommand
|
|
|
|
} e
|
|
|
|
set _ $e
|
|
|
|
} {*Unknown subcommand*}
|
|
|
|
|
|
|
|
test {FUNCTION - test loading from rdb} {
|
|
|
|
r debug reload
|
|
|
|
r fcall test 0
|
2021-12-19 10:41:51 -05:00
|
|
|
} {hello} {needs:debug}
|
2021-10-07 07:41:26 -04:00
|
|
|
|
Change FUNCTION CREATE, DELETE and FLUSH to be WRITE commands instead of MAY_REPLICATE. (#9953)
The issue with MAY_REPLICATE is that all automatic mechanisms to handle
write commands will not work. This require have a special treatment for:
* Not allow those commands to be executed on RO replica.
* Allow those commands to be executed on RO replica from primary connection.
* Allow those commands to be executed on the RO replica from AOF.
By setting those commands as WRITE commands we are getting all those properties from Redis.
Test was added to verify that those properties work as expected.
In addition, rearrange when and where functions are flushed. Before this PR functions were
flushed manually on `rdbLoadRio` and cleaned manually on failure. This contradicts the
assumptions that functions are data and need to be created/deleted alongside with the
data. A side effect of this, for example, `debug reload noflush` did not flush the data but
did flush the functions, `debug loadaof` flush the data but not the functions.
This PR move functions deletion into `emptyDb`. `emptyDb` (renamed to `emptyData`) will
now accept an additional flag, `NOFUNCTIONS` which specifically indicate that we do not
want to flush the functions (on all other cases, functions will be flushed). Used the new flag
on FLUSHALL and FLUSHDB only! Tests were added to `debug reload` and `debug loadaof`
to verify that functions behave the same as the data.
Notice that because now functions will be deleted along side with the data we can not allow
`CLUSTER RESET` to be called from within a function (it will cause the function to be released
while running), this PR adds `NO_SCRIPT` flag to `CLUSTER RESET` so it will not be possible
to be called from within a function. The other cluster commands are allowed from within a
function (there are use-cases that uses `GETKEYSINSLOT` to iterate over all the keys on a
given slot). Tests was added to verify `CLUSTER RESET` is denied from within a script.
Another small change on this PR is that `RDBFLAGS_ALLOW_DUP` is also applicable on functions.
When loading functions, if this flag is set, we will replace old functions with new ones on collisions.
2021-12-21 09:13:29 -05:00
|
|
|
test {FUNCTION - test debug reload different options} {
|
|
|
|
catch {r debug reload noflush} e
|
|
|
|
assert_match "*Error trying to load the RDB*" $e
|
|
|
|
r debug reload noflush merge
|
|
|
|
r function list
|
|
|
|
} {{name test engine LUA description {some description}}} {needs:debug}
|
|
|
|
|
|
|
|
test {FUNCTION - test debug reload with nosave and noflush} {
|
|
|
|
r function delete test
|
|
|
|
r set x 1
|
|
|
|
r function create LUA test1 DESCRIPTION {some description} {return 'hello'}
|
|
|
|
r debug reload
|
|
|
|
r function create LUA test2 DESCRIPTION {some description} {return 'hello'}
|
|
|
|
r debug reload nosave noflush merge
|
|
|
|
assert_equal [r fcall test1 0] {hello}
|
|
|
|
assert_equal [r fcall test2 0] {hello}
|
|
|
|
} {} {needs:debug}
|
|
|
|
|
|
|
|
test {FUNCTION - test flushall and flushdb do not clean functions} {
|
|
|
|
r function flush
|
|
|
|
r function create lua test REPLACE {return redis.call('set', 'x', '1')}
|
|
|
|
r flushall
|
|
|
|
r flushdb
|
|
|
|
r function list
|
|
|
|
} {{name test engine LUA description {}}}
|
|
|
|
|
2021-12-26 02:03:37 -05:00
|
|
|
test {FUNCTION - test function dump and restore} {
|
|
|
|
r function flush
|
|
|
|
r function create lua test description {some description} {return 'hello'}
|
|
|
|
set e [r function dump]
|
|
|
|
r function delete test
|
|
|
|
assert_match {} [r function list]
|
|
|
|
r function restore $e
|
|
|
|
r function list
|
|
|
|
} {{name test engine LUA description {some description}}}
|
|
|
|
|
|
|
|
test {FUNCTION - test function dump and restore with flush argument} {
|
|
|
|
set e [r function dump]
|
|
|
|
r function flush
|
|
|
|
assert_match {} [r function list]
|
|
|
|
r function restore $e FLUSH
|
|
|
|
r function list
|
|
|
|
} {{name test engine LUA description {some description}}}
|
|
|
|
|
|
|
|
test {FUNCTION - test function dump and restore with append argument} {
|
|
|
|
set e [r function dump]
|
|
|
|
r function flush
|
|
|
|
assert_match {} [r function list]
|
|
|
|
r function create lua test {return 'hello1'}
|
|
|
|
catch {r function restore $e APPEND} err
|
|
|
|
assert_match {*already exists*} $err
|
|
|
|
r function flush
|
|
|
|
r function create lua test1 {return 'hello1'}
|
|
|
|
r function restore $e APPEND
|
|
|
|
assert_match {hello} [r fcall test 0]
|
|
|
|
assert_match {hello1} [r fcall test1 0]
|
|
|
|
}
|
|
|
|
|
|
|
|
test {FUNCTION - test function dump and restore with replace argument} {
|
|
|
|
r function flush
|
|
|
|
r function create LUA test DESCRIPTION {some description} {return 'hello'}
|
|
|
|
set e [r function dump]
|
|
|
|
r function flush
|
|
|
|
assert_match {} [r function list]
|
|
|
|
r function create lua test {return 'hello1'}
|
|
|
|
assert_match {hello1} [r fcall test 0]
|
|
|
|
r function restore $e REPLACE
|
|
|
|
assert_match {hello} [r fcall test 0]
|
|
|
|
}
|
|
|
|
|
|
|
|
test {FUNCTION - test function restore with bad payload do not drop existing functions} {
|
|
|
|
r function flush
|
|
|
|
r function create LUA test DESCRIPTION {some description} {return 'hello'}
|
|
|
|
catch {r function restore bad_payload} e
|
|
|
|
assert_match {*payload version or checksum are wrong*} $e
|
|
|
|
r function list
|
|
|
|
} {{name test engine LUA description {some description}}}
|
|
|
|
|
|
|
|
test {FUNCTION - test function restore with wrong number of arguments} {
|
|
|
|
catch {r function restore arg1 args2 arg3} e
|
|
|
|
set _ $e
|
|
|
|
} {*wrong number of arguments*}
|
|
|
|
|
2021-10-07 07:41:26 -04:00
|
|
|
test {FUNCTION - test fcall_ro with write command} {
|
|
|
|
r function create lua test REPLACE {return redis.call('set', 'x', '1')}
|
|
|
|
catch { r fcall_ro test 0 } e
|
|
|
|
set _ $e
|
|
|
|
} {*Write commands are not allowed from read-only scripts*}
|
|
|
|
|
|
|
|
test {FUNCTION - test fcall_ro with read only commands} {
|
|
|
|
r function create lua test REPLACE {return redis.call('get', 'x')}
|
|
|
|
r set x 1
|
|
|
|
r fcall_ro test 0
|
|
|
|
} {1}
|
|
|
|
|
|
|
|
test {FUNCTION - test keys and argv} {
|
|
|
|
r function create lua test REPLACE {return redis.call('set', KEYS[1], ARGV[1])}
|
|
|
|
r fcall test 1 x foo
|
|
|
|
r get x
|
|
|
|
} {foo}
|
|
|
|
|
|
|
|
test {FUNCTION - test command get keys on fcall} {
|
|
|
|
r COMMAND GETKEYS fcall test 1 x foo
|
|
|
|
} {x}
|
|
|
|
|
|
|
|
test {FUNCTION - test command get keys on fcall_ro} {
|
|
|
|
r COMMAND GETKEYS fcall_ro test 1 x foo
|
|
|
|
} {x}
|
|
|
|
|
|
|
|
test {FUNCTION - test function kill} {
|
|
|
|
set rd [redis_deferring_client]
|
|
|
|
r config set script-time-limit 10
|
|
|
|
r function create lua test REPLACE {local a = 1 while true do a = a + 1 end}
|
|
|
|
$rd fcall test 0
|
|
|
|
after 200
|
|
|
|
catch {r ping} e
|
|
|
|
assert_match {BUSY*} $e
|
|
|
|
assert_match {running_script {name test command {fcall test 0} duration_ms *} engines LUA} [r FUNCTION STATS]
|
|
|
|
r function kill
|
|
|
|
after 200 ; # Give some time to Lua to call the hook again...
|
|
|
|
assert_equal [r ping] "PONG"
|
|
|
|
}
|
|
|
|
|
|
|
|
test {FUNCTION - test script kill not working on function} {
|
|
|
|
set rd [redis_deferring_client]
|
|
|
|
r config set script-time-limit 10
|
|
|
|
r function create lua test REPLACE {local a = 1 while true do a = a + 1 end}
|
|
|
|
$rd fcall test 0
|
|
|
|
after 200
|
|
|
|
catch {r ping} e
|
|
|
|
assert_match {BUSY*} $e
|
|
|
|
catch {r script kill} e
|
|
|
|
assert_match {BUSY*} $e
|
|
|
|
r function kill
|
|
|
|
after 200 ; # Give some time to Lua to call the hook again...
|
|
|
|
assert_equal [r ping] "PONG"
|
|
|
|
}
|
|
|
|
|
|
|
|
test {FUNCTION - test function kill not working on eval} {
|
|
|
|
set rd [redis_deferring_client]
|
|
|
|
r config set script-time-limit 10
|
|
|
|
$rd eval {local a = 1 while true do a = a + 1 end} 0
|
|
|
|
after 200
|
|
|
|
catch {r ping} e
|
|
|
|
assert_match {BUSY*} $e
|
|
|
|
catch {r function kill} e
|
|
|
|
assert_match {BUSY*} $e
|
|
|
|
r script kill
|
|
|
|
after 200 ; # Give some time to Lua to call the hook again...
|
|
|
|
assert_equal [r ping] "PONG"
|
|
|
|
}
|
2021-12-16 10:58:25 -05:00
|
|
|
|
|
|
|
test {FUNCTION - test function flush} {
|
|
|
|
r function create lua test REPLACE {local a = 1 while true do a = a + 1 end}
|
|
|
|
assert_match {{name test engine LUA description {}}} [r function list]
|
|
|
|
r function flush
|
|
|
|
assert_match {} [r function list]
|
|
|
|
|
|
|
|
r function create lua test REPLACE {local a = 1 while true do a = a + 1 end}
|
|
|
|
assert_match {{name test engine LUA description {}}} [r function list]
|
|
|
|
r function flush async
|
|
|
|
assert_match {} [r function list]
|
|
|
|
|
|
|
|
r function create lua test REPLACE {local a = 1 while true do a = a + 1 end}
|
|
|
|
assert_match {{name test engine LUA description {}}} [r function list]
|
|
|
|
r function flush sync
|
|
|
|
assert_match {} [r function list]
|
|
|
|
}
|
|
|
|
|
|
|
|
test {FUNCTION - test function wrong argument} {
|
|
|
|
catch {r function flush bad_arg} e
|
|
|
|
assert_match {*only supports SYNC|ASYNC*} $e
|
|
|
|
|
|
|
|
catch {r function flush sync extra_arg} e
|
|
|
|
assert_match {*wrong number of arguments*} $e
|
|
|
|
}
|
2021-10-07 07:41:26 -04:00
|
|
|
}
|
|
|
|
|
2021-12-16 10:58:25 -05:00
|
|
|
start_server {tags {"scripting repl external:skip"}} {
|
2021-10-07 07:41:26 -04:00
|
|
|
start_server {} {
|
|
|
|
test "Connect a replica to the master instance" {
|
|
|
|
r -1 slaveof [srv 0 host] [srv 0 port]
|
|
|
|
wait_for_condition 50 100 {
|
|
|
|
[s -1 role] eq {slave} &&
|
|
|
|
[string match {*master_link_status:up*} [r -1 info replication]]
|
|
|
|
} else {
|
|
|
|
fail "Can't turn the instance into a replica"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
test {FUNCTION - creation is replicated to replica} {
|
|
|
|
r function create LUA test DESCRIPTION {some description} {return 'hello'}
|
|
|
|
wait_for_condition 50 100 {
|
|
|
|
[r -1 function list] eq {{name test engine LUA description {some description}}}
|
|
|
|
} else {
|
|
|
|
fail "Failed waiting for function to replicate to replica"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
test {FUNCTION - call on replica} {
|
|
|
|
r -1 fcall test 0
|
|
|
|
} {hello}
|
|
|
|
|
2021-12-26 02:03:37 -05:00
|
|
|
test {FUNCTION - restore is replicated to replica} {
|
|
|
|
set e [r function dump]
|
|
|
|
|
|
|
|
r function delete test
|
|
|
|
wait_for_condition 50 100 {
|
|
|
|
[r -1 function list] eq {}
|
|
|
|
} else {
|
|
|
|
fail "Failed waiting for function to replicate to replica"
|
|
|
|
}
|
|
|
|
|
|
|
|
r function restore $e
|
|
|
|
|
|
|
|
wait_for_condition 50 100 {
|
|
|
|
[r -1 function list] eq {{name test engine LUA description {some description}}}
|
|
|
|
} else {
|
|
|
|
fail "Failed waiting for function to replicate to replica"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-07 07:41:26 -04:00
|
|
|
test {FUNCTION - delete is replicated to replica} {
|
|
|
|
r function delete test
|
|
|
|
wait_for_condition 50 100 {
|
|
|
|
[r -1 function list] eq {}
|
|
|
|
} else {
|
|
|
|
fail "Failed waiting for function to replicate to replica"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-16 10:58:25 -05:00
|
|
|
test {FUNCTION - flush is replicated to replica} {
|
|
|
|
r function create LUA test DESCRIPTION {some description} {return 'hello'}
|
|
|
|
wait_for_condition 50 100 {
|
|
|
|
[r -1 function list] eq {{name test engine LUA description {some description}}}
|
|
|
|
} else {
|
|
|
|
fail "Failed waiting for function to replicate to replica"
|
|
|
|
}
|
|
|
|
r function flush
|
|
|
|
wait_for_condition 50 100 {
|
|
|
|
[r -1 function list] eq {}
|
|
|
|
} else {
|
|
|
|
fail "Failed waiting for function to replicate to replica"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-07 07:41:26 -04:00
|
|
|
test "Disconnecting the replica from master instance" {
|
|
|
|
r -1 slaveof no one
|
|
|
|
# creating a function after disconnect to make sure function
|
|
|
|
# is replicated on rdb phase
|
|
|
|
r function create LUA test DESCRIPTION {some description} {return 'hello'}
|
|
|
|
|
|
|
|
# reconnect the replica
|
|
|
|
r -1 slaveof [srv 0 host] [srv 0 port]
|
|
|
|
wait_for_condition 50 100 {
|
|
|
|
[s -1 role] eq {slave} &&
|
|
|
|
[string match {*master_link_status:up*} [r -1 info replication]]
|
|
|
|
} else {
|
|
|
|
fail "Can't turn the instance into a replica"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
test "FUNCTION - test replication to replica on rdb phase" {
|
|
|
|
r -1 fcall test 0
|
|
|
|
} {hello}
|
|
|
|
|
|
|
|
test "FUNCTION - test replication to replica on rdb phase info command" {
|
|
|
|
r -1 function info test WITHCODE
|
|
|
|
} {name test engine LUA description {some description} code {return 'hello'}}
|
|
|
|
|
|
|
|
test "FUNCTION - create on read only replica" {
|
|
|
|
catch {
|
|
|
|
r -1 function create LUA test DESCRIPTION {some description} {return 'hello'}
|
|
|
|
} e
|
|
|
|
set _ $e
|
Change FUNCTION CREATE, DELETE and FLUSH to be WRITE commands instead of MAY_REPLICATE. (#9953)
The issue with MAY_REPLICATE is that all automatic mechanisms to handle
write commands will not work. This require have a special treatment for:
* Not allow those commands to be executed on RO replica.
* Allow those commands to be executed on RO replica from primary connection.
* Allow those commands to be executed on the RO replica from AOF.
By setting those commands as WRITE commands we are getting all those properties from Redis.
Test was added to verify that those properties work as expected.
In addition, rearrange when and where functions are flushed. Before this PR functions were
flushed manually on `rdbLoadRio` and cleaned manually on failure. This contradicts the
assumptions that functions are data and need to be created/deleted alongside with the
data. A side effect of this, for example, `debug reload noflush` did not flush the data but
did flush the functions, `debug loadaof` flush the data but not the functions.
This PR move functions deletion into `emptyDb`. `emptyDb` (renamed to `emptyData`) will
now accept an additional flag, `NOFUNCTIONS` which specifically indicate that we do not
want to flush the functions (on all other cases, functions will be flushed). Used the new flag
on FLUSHALL and FLUSHDB only! Tests were added to `debug reload` and `debug loadaof`
to verify that functions behave the same as the data.
Notice that because now functions will be deleted along side with the data we can not allow
`CLUSTER RESET` to be called from within a function (it will cause the function to be released
while running), this PR adds `NO_SCRIPT` flag to `CLUSTER RESET` so it will not be possible
to be called from within a function. The other cluster commands are allowed from within a
function (there are use-cases that uses `GETKEYSINSLOT` to iterate over all the keys on a
given slot). Tests was added to verify `CLUSTER RESET` is denied from within a script.
Another small change on this PR is that `RDBFLAGS_ALLOW_DUP` is also applicable on functions.
When loading functions, if this flag is set, we will replace old functions with new ones on collisions.
2021-12-21 09:13:29 -05:00
|
|
|
} {*can't write against a read only replica*}
|
2021-10-07 07:41:26 -04:00
|
|
|
|
|
|
|
test "FUNCTION - delete on read only replica" {
|
|
|
|
catch {
|
|
|
|
r -1 function delete test
|
|
|
|
} e
|
|
|
|
set _ $e
|
Change FUNCTION CREATE, DELETE and FLUSH to be WRITE commands instead of MAY_REPLICATE. (#9953)
The issue with MAY_REPLICATE is that all automatic mechanisms to handle
write commands will not work. This require have a special treatment for:
* Not allow those commands to be executed on RO replica.
* Allow those commands to be executed on RO replica from primary connection.
* Allow those commands to be executed on the RO replica from AOF.
By setting those commands as WRITE commands we are getting all those properties from Redis.
Test was added to verify that those properties work as expected.
In addition, rearrange when and where functions are flushed. Before this PR functions were
flushed manually on `rdbLoadRio` and cleaned manually on failure. This contradicts the
assumptions that functions are data and need to be created/deleted alongside with the
data. A side effect of this, for example, `debug reload noflush` did not flush the data but
did flush the functions, `debug loadaof` flush the data but not the functions.
This PR move functions deletion into `emptyDb`. `emptyDb` (renamed to `emptyData`) will
now accept an additional flag, `NOFUNCTIONS` which specifically indicate that we do not
want to flush the functions (on all other cases, functions will be flushed). Used the new flag
on FLUSHALL and FLUSHDB only! Tests were added to `debug reload` and `debug loadaof`
to verify that functions behave the same as the data.
Notice that because now functions will be deleted along side with the data we can not allow
`CLUSTER RESET` to be called from within a function (it will cause the function to be released
while running), this PR adds `NO_SCRIPT` flag to `CLUSTER RESET` so it will not be possible
to be called from within a function. The other cluster commands are allowed from within a
function (there are use-cases that uses `GETKEYSINSLOT` to iterate over all the keys on a
given slot). Tests was added to verify `CLUSTER RESET` is denied from within a script.
Another small change on this PR is that `RDBFLAGS_ALLOW_DUP` is also applicable on functions.
When loading functions, if this flag is set, we will replace old functions with new ones on collisions.
2021-12-21 09:13:29 -05:00
|
|
|
} {*can't write against a read only replica*}
|
2021-10-07 07:41:26 -04:00
|
|
|
|
|
|
|
test "FUNCTION - function effect is replicated to replica" {
|
|
|
|
r function create LUA test REPLACE {return redis.call('set', 'x', '1')}
|
|
|
|
r fcall test 0
|
|
|
|
assert {[r get x] eq {1}}
|
|
|
|
wait_for_condition 50 100 {
|
|
|
|
[r -1 get x] eq {1}
|
|
|
|
} else {
|
|
|
|
fail "Failed waiting function effect to be replicated to replica"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
test "FUNCTION - modify key space of read only replica" {
|
|
|
|
catch {
|
|
|
|
r -1 fcall test 0
|
|
|
|
} e
|
|
|
|
set _ $e
|
|
|
|
} {*can't write against a read only replica*}
|
|
|
|
}
|
Change FUNCTION CREATE, DELETE and FLUSH to be WRITE commands instead of MAY_REPLICATE. (#9953)
The issue with MAY_REPLICATE is that all automatic mechanisms to handle
write commands will not work. This require have a special treatment for:
* Not allow those commands to be executed on RO replica.
* Allow those commands to be executed on RO replica from primary connection.
* Allow those commands to be executed on the RO replica from AOF.
By setting those commands as WRITE commands we are getting all those properties from Redis.
Test was added to verify that those properties work as expected.
In addition, rearrange when and where functions are flushed. Before this PR functions were
flushed manually on `rdbLoadRio` and cleaned manually on failure. This contradicts the
assumptions that functions are data and need to be created/deleted alongside with the
data. A side effect of this, for example, `debug reload noflush` did not flush the data but
did flush the functions, `debug loadaof` flush the data but not the functions.
This PR move functions deletion into `emptyDb`. `emptyDb` (renamed to `emptyData`) will
now accept an additional flag, `NOFUNCTIONS` which specifically indicate that we do not
want to flush the functions (on all other cases, functions will be flushed). Used the new flag
on FLUSHALL and FLUSHDB only! Tests were added to `debug reload` and `debug loadaof`
to verify that functions behave the same as the data.
Notice that because now functions will be deleted along side with the data we can not allow
`CLUSTER RESET` to be called from within a function (it will cause the function to be released
while running), this PR adds `NO_SCRIPT` flag to `CLUSTER RESET` so it will not be possible
to be called from within a function. The other cluster commands are allowed from within a
function (there are use-cases that uses `GETKEYSINSLOT` to iterate over all the keys on a
given slot). Tests was added to verify `CLUSTER RESET` is denied from within a script.
Another small change on this PR is that `RDBFLAGS_ALLOW_DUP` is also applicable on functions.
When loading functions, if this flag is set, we will replace old functions with new ones on collisions.
2021-12-21 09:13:29 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
test {FUNCTION can processes create, delete and flush commands in AOF when doing "debug loadaof" in read-only slaves} {
|
|
|
|
start_server {} {
|
|
|
|
r config set appendonly yes
|
|
|
|
waitForBgrewriteaof r
|
|
|
|
r FUNCTION CREATE lua test "return 'hello'"
|
|
|
|
r config set slave-read-only yes
|
|
|
|
r slaveof 127.0.0.1 0
|
|
|
|
r debug loadaof
|
|
|
|
r slaveof no one
|
|
|
|
assert_equal [r function list] {{name test engine LUA description {}}}
|
|
|
|
|
|
|
|
r FUNCTION DELETE test
|
|
|
|
|
|
|
|
r slaveof 127.0.0.1 0
|
|
|
|
r debug loadaof
|
|
|
|
r slaveof no one
|
|
|
|
assert_equal [r function list] {}
|
|
|
|
|
|
|
|
r FUNCTION CREATE lua test "return 'hello'"
|
|
|
|
r FUNCTION FLUSH
|
|
|
|
|
|
|
|
r slaveof 127.0.0.1 0
|
|
|
|
r debug loadaof
|
|
|
|
r slaveof no one
|
|
|
|
assert_equal [r function list] {}
|
|
|
|
}
|
|
|
|
} {} {needs:debug external:skip}
|