Commit Graph

10836 Commits

Author SHA1 Message Date
Oran Agra
64f6159646
Merge Redis Functions PR (#9780)
# Redis Function
This PR added the Redis Functions capabilities that were suggested on #8693.
The PR also introduce a big refactoring to the current Lua implementation
(i.e `scripting.c`). The main purpose of the refactoring is to have better
code sharing between the Lua implementation that exists today on Redis
(`scripting.c`) and the new Lua engine that is introduced on this PR.
The refactoring includes code movements and file name changes as well as some
logic changes that need to be carefully reviewed. To make the review easier,
the PR was split into multiple commits. Each commit is deeply described later on
but the main concept is that some commits are just moving code around without
making any logical changes, those commits are less likely to cause any issues
or regressions and can be reviewed fast. Other commits, which perform code and
logic changes, need to be reviewed carefully, but those commits were created
after the code movements so it's pretty easy to see what was changed. To sum up,
it is highly recommended to review this PR commit by commit as it will be easier
to see the changes, it is also recommended to read each commit description
(written below) to understand what was changed on the commit and whether or not
it's just a huge code movement or a logic changes.

## Terminology
Currently, the terminology in Redis is not clearly defined. Scripts refer to Lua
scripts and eval also refers only to Lua. Introducing Redis Function requires
redefining those terms to be able to clearly understand what is been discussed
on each context.
* eval - legacy Lua script implementation.
* Function - new scripting implementation (currently implemented in Lua but in
  the future, it might be other languages like javascript).
* Engine - the component that is responsible for executing functions.
* Script - Function or legacy Lua (executed with `eval` or `evalsha`)

## Refactoring New Structure
Today, the entire scripting logic is located on `scripting.c`. This logic can
be split into 3 main groups:
1. Script management - responsible for storing the scripts that were sent to
   Redis and retrieving them when they need to be run (base on the script sha
   on the current implementation).
2. Script invocation - invoke the script given on `eval` or `evalsha` command
   (this part includes finding the relevant script, preparing the arguments, ..)
3. Interact back with Redis (command invocation)

Those 3 groups are tightly coupled on `scripting.c`. Redis Functions also need
to use those groups logics, for example,  to interact back with Redis or to
execute Lua code. The refactoring attempts to split those 3 groups and define
APIs so that we can reuse the code both on legacy Lua scripts and Redis Functions.

In order to do so we define the following units:
1. script.c: responsible for interaction with Redis from within a script.
2. script_lua.c: responsible to execute Lua code, uses `script.c` to interact
   with Redis from within the Lua code.
3. function_lua.c: contains the Lua engine implementation, uses `script_lua.c`
   to execute the Lua code.
4. functions.c: Contains Redis Functions implementation (`FUNCTION` command,),
   uses `functions_lua.c` if the function it wants to invoke needs the Lua
   engine.
4. eval.c: the original `scripting.c` contains the Lua legacy implementation and
   was refactored to use `script_lua.c` to invoke the Lua code.

## Commits breakdown
Notice: Some small commits are omitted from this list as they are small and
insignificant (for example build fixes)

### First commit - code movements
This commit rename `scripting.c` -> `eval.c` and introduce the new `script_lua.c`
unit. The commit moves relevant code from `eval.c` (`scripting.c`) to
`script_lua.c`, the purpose of moving the code is so that later we will be able
to re-use the code on the Lua engine (`function_lua.c`). The commit only moves
the code without modifying even a single line, so there is a very low risk of
breaking anything and it also makes it much easier to see the changes on the
following commits.
Because the commit does not change the code (only moves it), it does not compile.
But we do not care about it as the only purpose here is to make the review
processes simpler.

### Second commit - move legacy Lua variables into `eval.c`
Today, all Lua-related variables are located on the server struct. The commit
attempt to identify those variable and take them out from the server struct,
leaving only script related variables (variables that later need to be used
also by engines)
The following variable where renamed and left on the server struct:
   * lua_caller 			-> script_caller
   * lua_time_limit 		-> script_time_limit
   * lua_timedout 		-> script_timedout
   * lua_oom 			-> script_oom
   * lua_disable_deny_script 	-> script_disable_deny_script
   * in_eval			-> in_script

The following variables where moved to lctx under eval.c
   * lua
   * lua_client
   * lua_cur_script
   * lua_scripts
   * lua_scripts_mem
   * lua_replicate_commands
   * lua_write_dirty
   * lua_random_dirty
   * lua_multi_emitted
   * lua_repl
   * lua_kill
   * lua_time_start
   * lua_time_snapshot

This commit is in a low risk of introducing any issues and it is just moving
variables around and not changing any logic.

### Third commit - introducing script unit
This commit introduces the `script.c` unit. Its purpose (as described above) is
to provide an API for scripts to interact with Redis. Interaction includes
mostly executing commands, but also other functionalities. The interaction is
done using a `ScriptRunCtx` object that needs to be created by the user and
initialized using `scriptPrepareForRun`. A detailed list of functionalities
expose by the unit:
1. Calling commands (including all the validation checks such as
   acl, cluster, read only run, ...)
2. Set Resp
3. Set Replication method (AOF/REPLICATION/NONE)
4. Call Redis back on long-running scripts to allow Redis to reply to clients
   and perform script kill

The commit introduces the new unit and uses it on eval commands to interact with
Redis.

### Fourth commit - Moved functionality of invoke Lua code to `script_lua.c`
This commit moves the logic of invoking the Lua code into `script_lua.c` so
later it can be used also by Lua engine (`function_lua.c`). The code is located
on `callFunction` function and assumes the Lua function already located on the
top of the Lua stack. This commit also change `eval.c` to use the new
functionality to invoke Lua code.

### Fith commit - Added Redis Functions unit (`functions.c`) and Lua engine
(`function_lua.c`)
Added Redis Functions unit under `functions.c`, included:
1. FUNCTION command:
     * FUNCTION CREATE
     * FUNCTION CALL
     * FUNCTION DELETE
     * FUNCTION KILL
     * FUNCTION INFO
     * FUNCTION STATS
2. Register engines

In addition, this commit introduces the first engine that uses the Redis
Functions capabilities, the Lua engine (`function_lua.c`)

## API Changes
### `lua-time-limit`
configuration was renamed to `script-time-limit` (keep `lua-time-limit` as alias
for backward compatibility).

### Error log changes
When integrating with Redis from within a Lua script, the `Lua` term was removed
from all the error messages and instead we write only `script`. For example:
`Wrong number of args calling Redis command From Lua script` -> `Wrong number
of args calling Redis command From script`

### `info memory` changes:
Before stating all the changes made to memory stats we will try to explain the
reason behind them and what we want to see on those metrics:
* memory metrics should show both totals (for all scripting frameworks), as well
  as a breakdown per framework / vm.
* The totals metrics should have "human" metrics while the breakdown shouldn't.
* We did try to maintain backward compatibility in some way, that said we did
  make some repurpose to existing metrics where it looks reasonable.
* We separate between memory used by the script framework (part of redis's
  used_memory), and memory used by the VM (not part of redis's used_memory)

A full breakdown of `info memory` changes:
* `used_memory_lua` and `used_memory_lua_human` was deprecated,
  `used_memory_vm_eval` has the same meaning as `used_memory_lua`
* `used_memory_scripts` was renamed to `used_memory_scripts_eval`
* `used_memory_scripts` and `used_memory_scripts_human` were repurposed and now
  return the total memory used by functions and eval (not including vm memory,
  only code cache, and structs).
* `used_memory_vm_function` was added and represents the total memory used by
  functions vm's
* `used_memory_functions` was added and represents the total memory by functions
  (not including vm memory, only code cache, and structs)
* `used_memory_vm_total` and `used_memory_vm_total_human` was added and
  represents the total memory used by vm's (functions and eval combined)

### `functions.caches`
`functions.caches` field was added to `memory stats`, representing the memory
used by engines that are not functions (this memory includes data structures
like dictionaries, arrays, ...)

## New API
### FUNCTION CREATE

Usage: FUNCTION CREATE `ENGINE` `NAME` `[REPLACE]` `[DESC <DESCRIPTION>]` `<CODE>`

* `ENGINE` - The name of the engine to use to create the script.
* `NAME` - the name of the function that can be used later to call the function
  using `FUNCTION CALL` command.
* `REPLACE` - if given, replace the given function with the existing function
  (if exists).
* `DESCRIPTION` - optional argument describing the function and what it does
* `CODE` - function code.

The command will return `OK` if created successfully or error in the following
cases:
* The given engine name does not exist
* The function name is already taken and `REPLACE` was not used.
* The given function failed on the compilation.

### FCALL and FCALL_RO

Usage: FCALL/FCALL_RO `NAME` `NUM_KEYS key1 key2` … ` arg1 arg2`

Call and execute the function specified by `NAME`. The function will receive
all arguments given after `NUM_KEYS`. The return value from the function will
be returned to the user as a result.

* `NAME` - Name of the function to run.
* The rest is as today with EVALSHA command.

The command will return an error in the following cases:
* `NAME` does not exist
* The function itself returned an error.

The `FCALL_RO` is equivalent to `EVAL_RO` and allows only read-only commands to
be invoked from the script.

### FUNCTION DELETE

Usage: FUNCTION DELETE `NAME`

Delete a function identified by `NAME`. Return `OK` on success or error on one
of the following:
* The given function does not exist

### FUNCTION INFO

Usage: FUNCTION INFO `NAME` [WITHCODE]

Return information about a function by function name:
* Function name
* Engine name
* Description
* Raw code (only if WITHCODE argument is given)

### FUNCTION LIST

Usage: FUNCTION LIST

Return general information about all the functions:
* Function name
* Engine name
* Description

### FUNCTION STATS

Usage: FUNCTION STATS

Return information about the current running function:
* Function name
* Command that was used to invoke the function
* Duration in MS that the function is already running

If no function is currently running, this section is just a RESP nil.

Additionally, return a list of all the available engines.

### FUNCTION KILL

Usage: `FUNCTION KILL`

Kill the currently executing function. The command will fail if the function
already initiated a write command.

## Notes
Note: Function creation/deletion is replicated to AOF but AOFRW is not
implemented sense its going to be removed: #9794
2021-12-02 21:41:58 +02:00
meir@redislabs.com
cbd463175f Redis Functions - Added redis function unit and Lua engine
Redis function unit is located inside functions.c
and contains Redis Function implementation:
1. FUNCTION commands:
  * FUNCTION CREATE
  * FCALL
  * FCALL_RO
  * FUNCTION DELETE
  * FUNCTION KILL
  * FUNCTION INFO
2. Register engine

In addition, this commit introduce the first engine
that uses the Redis Function capabilities, the
Lua engine.
2021-12-02 19:35:52 +02:00
Binbin
e57a4db5d7
Fix CONFIG SET test failures in MacOS/FreeBSD (#9881)
After the introduction of `Multiparam config set` in #9748,
there are two tests cases failed.

```
[exception]: Executing test client: ERR Config set failed - Failed to set current oom_score_adj. Check server logs..
ERR Config set failed - Failed to set current oom_score_adj. Check server logs.
```

`CONFIG sanity` test failed on the `config set oom-score-adj-values`
which is a "special" config that does not catch no-op changes.
And then it will update `oom-score-adj` which not supported in
MacOs. We solve it by adding `oom-score*` to the `skip_configs` list.

```
*** [err]: CONFIG SET rollback on apply error in tests/unit/introspection.tcl
Expected an error but nothing was caught
```

`CONFIG SET rollback on apply error` test failed on the
`config set port $used_port`. In theory, it should throw the
error `Unable to listen on this port*`. But it failed on MacOs.
We solve it by adding `-myaddr 127.0.0.1` to the socket call.
2021-12-02 18:18:18 +02:00
Binbin
e3c0ea1cb4
Fix a harmless bug when using monitor in redis-cli with wrong reply (#9875)
When we use monitor in redis-cli but encounter an error reply,
we will get stuck until we press Ctrl-C to quit.

This is a harmless bug. It might be useful if we add parameters
to monitor in the future, suck as monitoring only selected db.

before:
```
127.0.0.1:6379> monitor wrong
(error) ERR wrong number of arguments for 'monitor' command or subcommand
^C(9.98s)
127.0.0.1:6379>
```

after:
```
127.0.0.1:6379> monitor wrong
(error) ERR wrong number of arguments for 'monitor' command or subcommand
127.0.0.1:6379>
```
2021-12-02 10:41:50 +02:00
meir@redislabs.com
f21dc38a6e Redis Functions - Moved invoke Lua code functionality to script_lua.c
The functionality was moved to script_lua.c under
callFunction function. Its purpose is to call the Lua
function already located on the top of the Lua stack.

Used the new function on eval.c to invoke Lua code.
The function will also be used to invoke Lua
code on the Lua engine.
2021-12-01 23:57:06 +02:00
meir@redislabs.com
fc731bc67f Redis Functions - Introduce script unit.
Script unit is a new unit located on script.c.
Its purpose is to provides an API for functions (and eval)
to interact with Redis. Interaction includes mostly
executing commands, but also functionalities like calling
Redis back on long scripts or check if the script was killed.

The interaction is done using a scriptRunCtx object that
need to be created by the user and initialized using scriptPrepareForRun.

Detailed list of functionalities expose by the unit:
1. Calling commands (including all the validation checks such as
   acl, cluster, read only run, ...)
2. Set Resp
3. Set Replication method (AOF/REPLICATION/NONE)
4. Call Redis back to on long running scripts to allow Redis reply
   to clients and perform script kill

The commit introduce the new unit and uses it on eval commands to
interact with Redis.
2021-12-01 23:54:23 +02:00
meir@redislabs.com
e0cd580aef Redis Functions - Move Lua related variable into luaCtx struct
The following variable was renamed:
1. lua_caller 			-> script_caller
2. lua_time_limit 		-> script_time_limit
3. lua_timedout 		-> script_timedout
4. lua_oom 			-> script_oom
5. lua_disable_deny_script 	-> script_disable_deny_script
6. in_eval			-> in_script

The following variables was moved to lctx under eval.c
1.  lua
2.  lua_client
3.  lua_cur_script
4.  lua_scripts
5.  lua_scripts_mem
6.  lua_replicate_commands
7.  lua_write_dirty
8.  lua_random_dirty
9.  lua_multi_emitted
10. lua_repl
11. lua_kill
12. lua_time_start
13. lua_time_snapshot

This commit is in a low risk of introducing any issues and it
is just moving varibales around and not changing any logic.
2021-12-01 23:31:08 +02:00
meir@redislabs.com
22aab1ce94 Redis Functions - Move code to make review process easier.
This commit is only move code around without changing it.
The reason behind this is to make review process easier
by allowing the reviewer to simply ignore all code movements.

changes:
1. rename scripting.c to eval.c
2. introduce and new file, script_lua.c, and move parts of Lua
   functionality to this new file. script_lua.c will eventually
   contains the shared code between legacy lua and lua engine.

This commit does not compiled on purpose. Its only purpose is to move
code and rename files.
2021-12-01 23:30:59 +02:00
yoav-steinberg
0e5b813ef9
Multiparam config set (#9748)
We can now do: `config set maxmemory 10m repl-backlog-size 5m`

## Basic algorithm to support "transaction like" config sets:

1. Backup all relevant current values (via get).
2. Run "verify" and "set" on everything, if we fail run "restore".
3. Run "apply" on everything (optional optimization: skip functions already run). If we fail run "restore".
4. Return success.

### restore
1. Run set on everything in backup. If we fail log it and continue (this puts us in an undefined
   state but we decided it's better than the alternative of panicking). This indicates either a bug
   or some unsupported external state.
2. Run apply on everything in backup (optimization: skip functions already run). If we fail log
   it (see comment above).
3. Return error.

## Implementation/design changes:
* Apply function are idempotent (have no effect if they are run more than once for the same config).
* No indication in set functions if we're reading the config or running from the `CONFIG SET` command
   (removed `update` argument).
* Set function should set some config variable and assume an (optional) apply function will use that
   later to apply. If we know this setting can be safely applied immediately and can always be reverted
   and doesn't depend on any other configuration we can apply immediately from within the set function
   (and not store the setting anywhere). This is the case of this `dir` config, for example, which has no
   apply function. No apply function is need also in the case that setting the variable in the `server` struct
   is all that needs to be done to make the configuration take effect. Note that the original concept of `update_fn`,
   which received the old and new values was removed and replaced by the optional apply function.
* Apply functions use settings written to the `server` struct and don't receive any inputs.
* I take care that for the generic (non-special) configs if there's no change I avoid calling the setter (possible
   optimization: avoid calling the apply function as well).
* Passing the same config parameter more than once to `config set` will fail. You can't do `config set my-setting
   value1 my-setting value2`.

Note that getting `save` in the context of the conf file parsing to work here as before was a pain.
The conf file supports an aggregate `save` definition, where each `save` line is added to the server's
save params. This is unlike any other line in the config file where each line overwrites any previous
configuration. Since we now support passing multiple save params in a single line (see top comments
about `save` in https://github.com/redis/redis/pull/9644) we should deprecate the aggregate nature of
this config line and perhaps reduce this ugly code in the future.
2021-12-01 10:15:11 +02:00
Itamar Haber
21aa1d4b91
Adds auto-seq-only-generation via XADD ... <ms>-* (#9217)
Adds the ability to autogenerate the sequence part of the millisecond-only explicit ID specified for `XADD`. This is useful in case added entries have an externally-provided timestamp without sub-millisecond resolution.
2021-11-30 19:56:39 +02:00
Wen Hui
2afa41f628
Sentinel master reboot fix (#9438)
Add master-reboot-down-after-period as a configurable parameter, to make it possible to trigger a failover from a master that is responding with `-LOADING` for a long time after being restarted.
2021-11-30 18:46:15 +02:00
丽媛自己动
af072c26bc
modify misleading note in comment (#9865)
now rdbSaveInfo used in both way, so i think we should update previous notes, in case of misleading
2021-11-30 14:10:49 +02:00
Viktor Söderqvist
bdf531e38d
Extend output of DEBUG HELP for POPULATE (#9869) 2021-11-30 12:36:52 +02:00
Meir Shpilraien (Spielrein)
b8e82d205b
Swap '\r\n' with spaces when returning a big number reply from Lua script. (#9870)
The issue can only happened with a bad Lua script that claims to return
a big number while actually return data which is not a big number (contains
chars that are not digits). Such thing will not cause an issue unless the big
number value contains `\r\n` and then it messes the resp3 structure. The fix
changes all the appearances of '\r\n' with spaces.

Such an issue can also happened on simple string or error replies but those
already handle it the same way this PR does (replace `\r\n` with spaces).

Other replies type are not vulnerable to this issue because they are not
counting on free text that is terminated with `\r\n` (either it contains the
bulk length like string reply or they are typed reply that can not inject free
text like boolean or number).

The issue only exists on unstable branch, big number reply on Lua script
was not yet added to any official release.
2021-11-30 12:27:05 +02:00
Binbin
3119a3aeb5
Fix CLIENT KILL kill all clients with id 0 (#9853)
* Fix CLIENT KILL kill all clients with id 0 or with skipme
CLIENT KILL with ID argument should only kill the client with the provided ID. In old code, 
CLIENT KILL with id 0 will kill all the connected clients.

Co-authored-by: Ofir Luzon <ofirluzon@gmail.com>
2021-11-29 13:35:36 -08:00
yoav-steinberg
2386e54182
fix deprecation of _BSD_SOURCE feature test macro (#9861)
caused a build warning in linenoise since glibc 2.20
2021-11-29 16:09:20 +02:00
OfirMos
9f9c78578f
fixed mem leak on rdb load error (#9860)
a rare case of short read that can happen when breaking the master-replica
connection on diskless load mode,
2021-11-29 12:09:08 +02:00
Binbin
980bb3ae19
Add REDIS_CFLAGS='-Werror' to CI tests (#9828)
Update CI so that warnings cause build failures.

Also fix a warning in `test-sanitizer-address`:
```
In function ‘strncpy’,
   inlined from ‘clusterUpdateMyselfIp’ at cluster.c:545:13:

/usr/include/x86_64-linux-gnu/bits/string_fortified.h:106:10:
error: ‘__builtin_strncpy’ specified bound 46 equals destination size [-Werror=stringop-truncation]

  106 |   return __builtin___strncpy_chk (__dest, __src, __len, __bos (__dest));
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
```
2021-11-29 10:30:35 +02:00
leishiao
d56ded89c5
improvement of a blocking xread test (#9859)
This test relies on that `XREAD BLOCK 20000 STREAMS s1{t} s2{t} s3{t} $ $ $`
is executed by redis before `XADD s2{t} * new abcd1234`. A ` wait_for_blocked_client`
is needed between the two to ensure the order, otherwise `XADD s2{t} * new abcd1234`
might be executed first due to network delay causing a test failure.

Co-authored-by: xiaolei <xiaolei@91jkys.com>
2021-11-29 09:57:21 +02:00
sundb
494ee2f1fc
Fix abnormal compression due to out-of-control recompress (#9849)
This pr is following #9779 .

## Describe of feature
Now when we turn on the `list-compress-depth` configuration, the list will compress
the ziplist between `[list-compress-depth, -list-compress-depth]`.
When we need to use the compressed data, we will first decompress it, then use it,
and finally compress it again.
It's controlled by `quicklistNode->recompress`, which is designed to avoid the need to
re-traverse the entire quicklist for compression after each decompression, we only need
to recompress the quicklsitNode being used.
In order to ensure the correctness of recompressing, we should normally let
quicklistDecompressNodeForUse and quicklistCompress appear in pairs, otherwise,
it may lead to the head and tail being compressed or the middle ziplist not being
compressed correctly, which is exactly the problem this pr needs to solve.

## Solution
1. Reset `quicklistIter` after insert and replace.
    The quicklist node will be compressed in `quicklistInsertAfter`, `quicklistInsertBefore`,
   `quicklistReplaceAtIndex`, so we can safely reset the quicklistIter to avoid it being used again
2. `quicklistIndex` will return an iterator that can be used to recompress the current node after use.
    
## Test
1. In the `Stress Tester for #3343-Similar Errors` test, when the server crashes or when
   `valgrind` or `asan` error is detected, print violating commands.
2. Add a crash test due to wrongly recompressing after `lrem`.
3. Remove `insert before with 0 elements` and `insert after with 0 elements`,
   Now we forbid any operation on an NULL quicklistIter.
2021-11-29 07:57:01 +02:00
Binbin
8759c1e14b
Improve stability in some blocking command tests (#9856)
In order to test the situation where multiple clients are
blocked, we set up multiple clients to execute some blocking
commands. These tests depend on the order of command processing.

Those tests are based on the wrong assumption that the command
send first will be executed by the server first, which is obviously
wrong in some network delyas.

This commit ensures orderly execution of commands by waiting
and judging the number of blocked clients each time.

Fix #9850
2021-11-28 15:37:35 +02:00
Meir Shpilraien (Spielrein)
6b0b04f1b2
Clean Lua stack before parsing call reply to avoid crash on a call with many arguments (#9809)
This commit 0f8b634cd (CVE-2021-32626 released in 6.2.6, 6.0.16, 5.0.14)
fixes an invalid memory write issue by using `lua_checkstack` API to make
sure the Lua stack is not overflow. This fix was added on 3 places:
1. `luaReplyToRedisReply`
2. `ldbRedis`
3. `redisProtocolToLuaType`

On the first 2 functions, `lua_checkstack` is handled gracefully while the
last is handled with an assert and a statement that this situation can
not happened (only with misbehave module):

> the Redis reply might be deep enough to explode the LUA stack (notice
that currently there is no such command in Redis that returns such a nested
reply, but modules might do it)

The issue that was discovered is that user arguments is also considered part
of the stack, and so the following script (for example) make the assertion reachable:
```
local a = {}
for i=1,7999 do
    a[i] = 1
end 
return redis.call("lpush", "l", unpack(a))
```

This is a regression because such a script would have worked before and now
its crashing Redis. The solution is to clear the function arguments from the Lua
stack which makes the original assumption true and the assertion unreachable.
2021-11-28 11:59:39 +02:00
Meir Shpilraien (Spielrein)
a8c1253b6f
Fix Lua C API violation on lua msgpack lib. (#9832)
msgpack lib missed using lua_checkstack and so on rare
cases overflow the stack by at most 2 elements. This is a
violation of the Lua C API. Notice that Lua allocates
additional 5 more elements on top of lua->stack_last
so Redis does not access an invalid memory. But it is an
API violation and we should avoid it.

This PR also added a new Lua compilation option. The new
option can be enable using environment variable called
LUA_DEBUG. If set to `yes` (by default `no`), Lua will be
compiled without optimizations and with debug symbols (`-O0 -g`).
In addition, in this new mode, Lua will be compiled with the
`-DLUA_USE_APICHECK` flag that enables extended Lua C API
validations.

In addition, set LUA_DEBUG=yes on daily valgrind flow so we
will be able to catch Lua C API violations in the future.
2021-11-28 11:33:09 +02:00
Viktor Söderqvist
acf3495eb8
Sort out the mess around writable replicas and lookupKeyRead/Write (#9572)
Writable replicas now no longer use the values of expired keys. Expired keys are
deleted when lookupKeyWrite() is used, even on a writable replica. Previously,
writable replicas could use the value of an expired key in write commands such
as INCR, SUNIONSTORE, etc..

This commit also sorts out the mess around the functions lookupKeyRead() and
lookupKeyWrite() so they now indicate what we intend to do with the key and
are not affected by the command calling them.

Multi-key commands like SUNIONSTORE, ZUNIONSTORE, COPY and SORT with the
store option now use lookupKeyRead() for the keys they're reading from (which will
not allow reading from logically expired keys).

This commit also fixes a bug where PFCOUNT could return a value of an
expired key.

Test modules commands have their readonly and write flags updated to correctly
reflect their lookups for reading or writing. Modules are not required to
correctly reflect this in their command flags, but this change is made for
consistency since the tests serve as usage examples.

Fixes #6842. Fixes #7475.
2021-11-28 11:26:28 +02:00
sundb
4d8700786e
Fix COMMAND GETKEYS on LCS (#9852)
Remove lcsGetKeys to clean up the remaining STRALGO after #9733.
i.e. it still used a getkeys_proc which was still looking for the KEYS or STRINGS arguments
2021-11-28 09:02:38 +02:00
Huang Zhw
596635fa0c
Cleanup: fix typo and remove some obsoleting definitions. (#9851) 2021-11-27 14:47:51 -08:00
uriyage
fa48fb2d0f
Do not watch keys for dirty client (#9829)
Currently, the watching clients are marked as dirty when a watched
key is touched, but we continue watching the keys for no reason.
Then, when the same key is touched again, we iterate again on the
watching clients list and mark all clients as dirty again.
Only when the exec/unwatch command is issued will the client be
removed from the key->watching_clients list. The same applies when
a dirty client calls the WATCH command. The key will be added to be
watched by the client even if it has no effect.

In the field, no performance degradation was observed as a result of the
current implementation; it is merely a cleanup with possible memory and
performance gains in some situations.

Co-authored-by: Oran Agra <oran@redislabs.com>
2021-11-25 15:23:15 +02:00
Pavel Melkozerov
9630ded313
fix fob bad log messages in rdbSave (#9842) (#9843)
logs message prints wrong file is failed to open temporary file
logs have error occurred in getcwd (uses same errno to report error)

Co-authored-by: Pavel Melkozerov <pavel.melkozerov@nokia.com>
2021-11-24 16:01:39 +02:00
sundb
4512905961
Replace ziplist with listpack in quicklist (#9740)
Part three of implementing #8702, following #8887 and #9366 .

## Description of the feature
1. Replace the ziplist container of quicklist with listpack.
2. Convert existing quicklist ziplists on RDB loading time. an O(n) operation.

## Interface changes
1. New `list-max-listpack-size` config is an alias for `list-max-ziplist-size`.
2. Replace `debug ziplist` command with `debug listpack`.

## Internal changes
1. Add `lpMerge` to merge two listpacks . (same as `ziplistMerge`)
2. Add `lpRepr` to print info of listpack which is used in debugCommand and `quicklistRepr`. (same as `ziplistRepr`)
3. Replace `QUICKLIST_NODE_CONTAINER_ZIPLIST` with `QUICKLIST_NODE_CONTAINER_PACKED`(following #9357 ).
    It represent that a quicklistNode is a packed node, as opposed to a plain node.
4. Remove `createZiplistObject` method, which is never used.
5. Calculate listpack entry size using overhead overestimation in `quicklistAllowInsert`.
    We prefer an overestimation, which would at worse lead to a few bytes below the lowest limit of 4k.

## Improvements
1. Calling `lpShrinkToFit` after converting Ziplist to listpack, which was missed at #9366.
2. Optimize `quicklistAppendPlainNode` to avoid memcpy data.

## Bugfix
1. Fix crash in `quicklistRepr` when ziplist is compressed, introduced from #9366.

## Test
1. Add unittest for `lpMerge`.
2. Modify the old quicklist ziplist corrupt dump test.

Co-authored-by: Oran Agra <oran@redislabs.com>
2021-11-24 13:34:13 +02:00
Binbin
fb4f7be22c
Wait for asyn_loading to stop in short read test (#9841)
In #9323, when `repl-diskless-load` is enabled and set to `swapdb`,
if the master replication ID hasn't changed, we can load data-set
asynchronously, and serving read commands during the full resync.

In `diskless loading short read` test, after a loading successfully,
we will wait for the loading to stop and continue the for loop.

After the introduction of `async_loading`, we also need to check it.
Otherwise the next loop will start too soon, may trigger a timing issue.
2021-11-24 12:46:43 +02:00
Binbin
9273d09dd4
Add tests to cover EXPIRE overflow fix (#9839)
In #8287, some overflow checks have been added. But when
`when *= 1000` overflows, it will become a positive number.
And the check not able to catch it. The key will be added with
a short expiration time and will deleted a few seconds later.

In #9601, will check the overflow after `*=` and return an
error first, and avoiding this situation.

In this commit, added some tests to cover those code paths.
Found it in #9825, and close it.
2021-11-24 09:39:23 +02:00
Oran Agra
a3a014294f
fix invalid read on corrupt ziplist (#9831)
If the last bytes in ziplist are corrupt and we decode from tail to head,
we may reach slightly outside the ziplist.
2021-11-23 14:56:52 +02:00
guybe7
b161cff5f9
QUIT is a command, HOST: and POST are not (#9798)
Some people complain that QUIT is missing from help/command table.
Not appearing in COMMAND command, command stats, ACL, etc.
and instead, there's a hack in processCommand with a comment that looks outdated.
Note that it is [documented](https://redis.io/commands/quit)

At the same time, HOST: and POST are there in the command table although these are not real commands.
They would appear in the COMMAND command, and even in commandstats.

Other changes:
1. Initialize the static logged_time static var in securityWarningCommand
2. add `no-auth` flag to RESET so it can always be executed.
2021-11-23 10:38:25 +02:00
Oran Agra
f07dedf73f
Fix invalid access in lpFind on corrupted listpack (#9819)
Issue found by corrupt-dump-fuzzer test with ASAN.
The problem was that lpSkip and lpGetWithSize could read the next listpack entry without validating that it's in range.
Similarly even the memcmp in lpFind could do that and possibly crash on segfault and now they'll crash on assert first.

The naive fix of using lpAssertValidEntry every time, resulted in 30% degradation in the lpFind benchmark of the unit test.
The final fix with the condition at the bottom has no performance implications.
2021-11-22 15:30:00 +02:00
Oran Agra
f00a8ad93c
fix string escaping in corrupt-dump test to support TCL8.5 (#9824)
TCL8.5 can't handle cases where part of the string is escaped and part of it isn't,
if there's a single char that needs escaping, we need to escape the whole string.
2021-11-22 12:30:06 +02:00
Binbin
698b577413
Fix timing issue in sub-second expires test (#9821)
The `PEXPIRE/PSETEX/PEXPIREAT can set sub-second expires` test is
a very time sensitive test, it used to occasionally fail on MacOS.

It will perform there internal tests in a loop, as long as one
fails, it will try to excute again in the next loop.

oranagra suggested that we can split it into three individual tests,
so that if one fails, we do not need to retry the others. And maybe
it will increase the chances of success dramatically.

Each is executed 500 times, and the number of retries is collected:
```
PSETEX, total: 500, sum: 745, min: 0, max: 13, avg: 1.49

PEXPIRE, total: 500, sum: 575, min: 0, max: 16, avg: 1.15

PEXPIREAT, total: 500, sum: 0, min: 0, max: 0, avg: 0.0

ALL(old_way), total: 500, sum: 8090, min: 0, max: 138, avg: 16.18
```

And we can see the threshold is very low.
Splitting the test also makes the code better to maintain.

Co-authored-by: Oran Agra <oran@redislabs.com>
2021-11-22 08:39:27 +02:00
Oran Agra
183b90a625
Fix false positive leak reported by GCC ASAN (#9816)
Leak found by the corrupt-dump-fuzzer when using GCC ASAN, which seems
to falsely report leaks on pointers kept only on the stack when calling exit.
Instead we now use _exit on panic / assert to skip these leak checks.

Additionally, check for sanitizer warnings in the corrupt-dump-fuzzer between iterations,
so that when something is found we know which test to relate it too (and it prints reproduction command list)
2021-11-21 18:47:10 +02:00
Ozan Tezcan
a68b71ac02
Don't use accurate option with ASAN unit tests (#9818)
specifically the ziplist and listpack unit tests and benchmarks run for too long with address sanitizer and --accurate
2021-11-21 18:27:54 +02:00
Yossi Gottlieb
fd0ca74763
Fix occasional RM_Call() crashes. (#9805)
With dynamically growing argc (#9528), it is necessary to initialize
argv_len. Normally createClient() handles that, but in the case of a
module shared_client, this needs to be done explicitly.

This also addresses an issue with rewriteClientCommandArgument() which
doesn't properly handle the case where the new element extends beyond
argc but not beyond argv_len.
2021-11-21 15:54:14 +02:00
Oran Agra
1417648469
Prevent LCS from allocating temp memory over proto-max-bulk-len (#9817)
LCS can allocate immense amount of memory (sizes of two inputs multiplied by each other).
In the past this caused some possible security issues due to overflows, which we solved
and also added use of `trymalloc` to return "Insufficient memory" instead of OOM panic zmalloc.

But in case overcommit is enabled, it could be that we won't get the OOM panic, and zmalloc
will succeed, and then we can get OOM killed by the kernel.

The solution here is to prevent LCS from allocating transient memory that's bigger than
`proto-max-bulk-len` config.
This config is not directly related to transient memory, but using a hard coded value ad well as
introducing a specific config seems wrong.

This comes to solve an error in the corrupt-dump-fuzzer test that started in the daily CI see #9799
2021-11-21 14:30:20 +02:00
Oran Agra
d4e7ffb38c
Improve active defrag in jemalloc 5.2 (#9778)
Background:
Following the upgrade to jemalloc 5.2, there was a test that used to be flaky and
started failing consistently (on 32bit), so we disabled it ​(see #9645).

This is a test that i introduced in #7289 when i attempted to solve a rare stagnation
problem, and it later turned out i failed to solve it, ans what's more i added a test that
caused it to be not so rare, and as i mentioned, now in jemalloc 5.2 it became consistent on 32bit.

Stagnation can happen when all the slabs of the bin are equally utilized, so the decision
to move an allocation from a relatively empty slab to a relatively full one, will never
happen, and in that test all the slabs are at 50% utilization, so the defragger could just
keep scanning the keyspace and not move anything.

What this PR changes:
* First, finally in jemalloc 5.2 we have the count of non-full slabs, so when we compare
  the utilization of the current slab, we can compare it to the average utilization of the non-full
  slabs in our bin, instead of the total average of our bin. this takes the full slabs out of the game,
  since they're not candidates for migration (neither source nor target).
* Secondly, We add some 12% (100/8) to the decision to defrag an allocation, this is the part
  that aims to avoid stagnation, and it's especially important since the above mentioned change
  can get us closer to stagnation.
* Thirdly, since jemalloc 5.2 adds sharded bins, we take into account all shards (something
  that's missing from the original PR that merged it), this isn't expected to make any difference
  since anyway there should be just one shard.

How this was benchmarked.
What i did was run the memefficiency test unit with `--verbose` and compare the defragger hits
and misses the tests reported.
At first, when i took into consideration only the non-full slabs, it got a lot worse (i got into
stagnation, or just got a lot of misses and a lot of hits), but when i added the 10% i got back
to results that were slightly better than the ones of the jemalloc 5.1 branch. i.e. full defragmentation
was achieved with fewer hits (relocations), and fewer misses (keyspace scans).
2021-11-21 13:35:39 +02:00
Madelyn Olson
362b3b02e6
Initialize manual failover replica target (#9814) 2021-11-19 19:56:44 -08:00
RuiliF
b567d3694c
fix memory leak in example module hellocluster (#9813)
Missing RedisModule_FreeCallReply
2021-11-20 00:48:08 +02:00
Yossi Gottlieb
366d5101d3
Tests: add a few missing needs:debug tags. (#9806) 2021-11-18 23:01:56 +02:00
Wen Hui
75d50e5de9
Fix module doc - missing function due to blank line (#9807) 2021-11-18 21:07:53 +02:00
perryitay
0c10f0e1c0
Fix crashes when list-compress-depth is used. (#9779)
Recently we started using list-compress-depth in tests (was completely untested till now).
Turns this triggered test failures with the external mode, since the tests left the setting enabled
and then it was used in other tests (specifically the fuzzer named "Stress tester for #3343-alike bugs").

This PR fixes the issue of the `recompress` flag being left set by mistake, which caused the code to
later to compress the head or tail nodes (which should never be compressed)

The solution is to reset the recompress flag when it should have been (when it was decided not to compress).

Additionally we're adding some assertions and improve the tests so in order to catch other similar bugs.
2021-11-18 18:09:30 +02:00
Binbin
020092e08f
Add --dump-logs to ci tests and daily tests (#9803)
So that we can print server log on test failure.
2021-11-18 16:04:01 +02:00
Eduardo Semprebon
1a255e3150
Reject PING with MASTERDOWN when replica-serve-stale-data=no (#9757)
Currently PING returns different status when server is not serving data,
for example when `LOADING` or `BUSY`.
But same was not true for `MASTERDOWN`
This commit makes PING reply with `MASTERDOWN` when
replica-serve-stale-data=no and link is MASTER is down.
2021-11-18 10:53:17 +02:00
guybe7
af7489886d
Obliterate STRALGO! add LCS (which only works on keys) (#9799)
Drop the STRALGO command, now LCS is a command of its own and it only works on keys (not input strings).
The motivation is that STRALGO's syntax was really messed-up...
- assumes all (future) string algorithms will take similar arguments
- mixes command that takes keys and one that doesn't in the same command.
- make it nearly impossible to expose the right key spec in COMMAND INFO (issues cluster clients)
- hard for cluster clients to determine the key names (firstkey, lastkey, etc)
- hard for ACL / flags (is it a read command?)

This is a breaking change.
2021-11-18 10:47:49 +02:00
Binbin
91e77a0cfb
Fixes ZPOPMIN/ZPOPMAX wrong replies when count is 0 with non-zset (#9711)
Moves ZPOP ... 0 fast exit path after type check to reply with
WRONGTYPE. In the past it will return an empty array.

Also now count is not allowed to be negative.

see #9680

before:
```
127.0.0.1:6379> set zset str
OK
127.0.0.1:6379> zpopmin zset 0
(empty array)
127.0.0.1:6379> zpopmin zset -1
(empty array)
```

after:
```
127.0.0.1:6379> set zset str
OK
127.0.0.1:6379> zpopmin zset 0
(error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> zpopmin zset -1
(error) ERR value is out of range, must be positive
```
2021-11-18 10:13:16 +02:00