Commit graph

12701 commits

Author SHA1 Message Date
alonre24
b99ca67ec3
RediSearch v8.2.1 (#14269)
* Protect cursors that are running in the background for FT.AGGREGATE
command while running FLUSHDB and avoid server crash -
https://github.com/RediSearch/RediSearch/pull/6601
* Fix performance regression in `info` command upon computing search
indexes memory due to a change in Trie data structure implementation,
and having it in O(1) again -
https://github.com/RediSearch/RediSearch/pull/6621
2025-08-13 22:26:02 +03:00
Stav-Levi
eac48279ad
Add auto-repair options for broken AOF tail on startup (#14058)
When Redis is shut down uncleanly (e.g., due to power loss), invalid
bytes may remain at the end of the AOF file. Currently, Redis detects
such corruption only after parsing most of the AOF, leading to delayed
error detection and increased downtime. Manual recovery via
`redis-check-aof --fix` is also time-consuming.

This fix introduces two new options to improve resilience and reduce
downtime:

- `aof-load-broken`: Enables automatic detection and repair of broken
AOF tails.
- `aof-load-broken-max-size`: Sets a maximum threshold (in bytes) for
the corrupted tail size that Redis will attempt to fix automatically
without requiring user intervention.
2025-08-12 10:55:16 +03:00
Salvatore Sanfilippo
674b829981
VSIM EPSILON fixes (#14223)
Hi, this PR implements the following changes:

1. The EPSILON option of VSIM is now documented.
2. The EPSILON behavior was fixed: the score was incorrectly divided by
two in the meaning, with a 0-2 interval provided by the underlying
cosine similarity, instead of the 0-1 interval. So an EPSILON of 0.2
only returned elements with a distance between 1 and 0.9 instead of 1
and 0.8. This is a *breaking change* but the command was not documented
so far, and it is a fix, as the user sees the similarity score so was a
total mismatch. I believe this fix should definitely be back ported as
soon as possible.
3. There are now tests.

Thanks for checking,
Salvatore
2025-08-12 11:45:35 +08:00
Ozan Tezcan
e03a4584fa
Fix flaky repl test by increasing key count to capture LOADING reply (#14265)
Increased replica key count to make flush take longer, ensuring the test
catches the `-LOADING` reply reliably.
2025-08-11 09:26:05 +03:00
h.o.t. neglected
3fa7a656f1
Fix memory leak in RM_GetCommandKeysWithFlags (#14243)
Fix https://github.com/redis/redis/issues/14208
As mentioned in the above issue, RM_GetCommandKeysWithFlags could have
memory leak when the number of keys is larger than MAX_KEYS_BUFFER. This
PR fixes it by calling getKeysFreeResult before the function's return. A
TCL testcase is created to verify the fix.
2025-08-06 15:09:08 +08:00
Stav-Levi
7b40dbacdf
Fix timing issue for correct replication disconnection time counters behavior test (#14221)
Co-authored-by: debing.sun <debing.sun@redis.com>
2025-08-06 15:07:30 +08:00
Chris Lamb
0ac04bbd14
Add "Redis ver. $REDIS_VERSION" to LOLWUT 8 output (#14195)
eg. python-redis
(https://github.com/redis/redis-py/blob/master/tests/test_commands.py#L1092)

---------

Co-authored-by: debing.sun <debing.sun@redis.com>
2025-08-06 15:04:47 +08:00
Slavomir Kaslev
ecc3cbfde8
Move getSlotOrReply() to cluster.c (#14253)
getSlotOrReply() is used by the `CLUSTER SLOT-STATS` command but is
defined
in cluster_legacy.c which might not be present in all build
configurations.
2025-08-04 14:42:30 +03:00
kei-nan
ff2f0b092c
Avoid Accessing Arguments Out Of Bounds In handleDebugClusterCommand (#14242)
Noticed we assume there are at least 3 arguments since we access to
index 2 in the if and only later check the argc.
Moved the argc check to the start of the if so the code will be a bit
safer.
2025-08-01 11:53:56 +08:00
Moti Cohen
c55e33a99f
KEYSIZES - Fix resolving key slot on modules (#14240)
In cluster mode with modules, for a given key, the slot resolution for
the KEYSIZES histogram update was incorrect. As a result, the histogram
might gracefully ignored those keys instead or update the wrong slot
histogram.
2025-07-31 15:44:25 +03:00
Eran Hadad
c636d80a77
Update Bloom, Json, and Timeserise to 8.2.0 (#14230) 2025-07-31 12:00:44 +03:00
alonre24
96ff42b20e
Bump RediSearch to 8.2.0 (#14232)
* Expose more compression variants for the new SVS-VAMANA vector index -
https://github.com/RediSearch/RediSearch/pull/6430
* Add the optional `SHARD_K_RATIO` parameter for KNN vector query in a
cluster environment to favor network latency reduction at the expense of
accuracy (under unsatble features) -
https://github.com/RediSearch/RediSearch/pull/6531,
https://github.com/RediSearch/RediSearch/pull/6535
2025-07-31 11:55:31 +03:00
YaacovHazan
4604407fdd
Use safe Iterator for modules (#14239) 2025-07-31 11:51:26 +03:00
YaacovHazan
9b6fb47603
Remove string cat usage in tcl tests in order to support tcl8.5 (#14238)
Co-authored-by: Mincho Paskalev <minchopaskal@gmail.com>
2025-07-31 11:51:04 +03:00
debing.sun
bec644aab1
Fix missing kvobj reassignment after reallocation in MOVE command (#14233)
Introduced by https://github.com/redis/redis/issues/13806

Fixed a crash in the MOVE command when moving hash objects that have
both key expiration and field expiration.

The issue occurred in the following scenario:
1. A hash has both key expiration and field expiration.
2. During MOVE command, `setExpireByLink()` is called to set the
expiration time for the target hash, which may reallocate the kvobj of
hash.
3. Since the hash has field expiration, `hashTypeAddToExpires()` is
called to update the minimum field expiration time

Issue:
However, the kvobj pointer wasn't updated with the return value from
`setExpireByLink()`, causing `hashTypeAddToExpires()` to use freed
memory.
2025-07-30 22:24:56 +08:00
debing.sun
333f679e89
Fix timeout issues in memefficiency.tcl (#14231)
Follow https://github.com/redis/redis/pull/14217
Fix https://github.com/redis/redis/issues/14196

Fix two other issues that might cause timeouts due to command writing
via pipe.
2025-07-30 21:47:51 +08:00
Yuan Wang
db4fc2a833
Fix HINCRBYFLOAT removes field expiration on replica (#14224)
Fixes #14218

Before, we replicate HINCRBYFLOAT as an HSET command with the final
value in order to make sure that differences in float precision or
formatting will not create differences in replicas or after an AOF
restart.
However, on the replica side, if the field has an expiration time, HSET
will remove it, even though the master retains it. This leads to
inconsistencies between the master and the replica.

To address this, we now use the HSETEX command with the KEEPTTL flag
instead of HSET, ensuring that the field’s TTL is preserved.

This bug was introduced in version 7.4, but the HSETEX command was only
implemented from version 8.0. Therefore, this patch does not fix the
issue in the 7.4 branch, a separate commit is needed to address it in
7.4.
2025-07-28 21:09:46 +08:00
Ozan Tezcan
e9d2bf48e0
Skip replication test due to flakiness under TSAN (#14225) 2025-07-28 17:55:09 +08:00
Stav-Levi
3ed9460aa6
handle SET KEEPTTL in the optimization path
Fixed bug where SET key value after SET key value EX seconds would not
remove the TTL as expected. The issue was in dbSetValue()'s optimization
path which was missing TTL handling logic.
2025-07-28 10:19:33 +03:00
Stav-Levi
82396716d0
Add API to allow Redis modules to unsubscribe from keyspace notifications
This API complements module subscribe by enabling modules to unsubscribe
from specific keyspace event notifications when they are no longer
needed.
This helps reduce performance overhead and unnecessary callback
invocations.

The function matches subscriptions based on event mask, callback
pointer,
and module identity. If a matching subscription is found, it is removed.

Returns REDISMODULE_OK if a subscription was successfully removed,
otherwise REDISMODULE_ERR.
2025-07-28 10:17:48 +03:00
debing.sun
fe3f0aa252
Fix some daily CI issues (#14217)
1) Fix the timeout of `Active defrag big keys: standalone`
Using a pipe to write commands may cause the write to block if the read
buffer becomes full.

2) Fix the failure of `Main db not affected when fail to diskless load`
test
If the master was killed in slow environment, then after
`cluster-node-timeout` (3s in our test), running keyspace commands on
the replica will get a CLUSTERDOWN error.

3) Fix the failure of `Test shutdown hook` test
ASAN can intercept a signal, so I guess that when we send SIGCONT after
SIGTERM to kill the server, it might start doing some work again,
causing the process to close very slowly.
2025-07-28 10:53:57 +08:00
debing.sun
ecd5e639ed
CLIENT UNBLOCK should't be able to unpause paused clients (#14164)
This PR is based on https://github.com/valkey-io/valkey/pull/2117

When a client is blocked by something like `CLIENT PAUSE`, we should not
allow `CLIENT UNBLOCK timeout` to unblock it, since some blocking types
does not has the timeout callback, it will trigger a panic in the core,
people should use `CLIENT UNPAUSE` to unblock it.

Also using `CLIENT UNBLOCK error` is not right, it will return a
UNBLOCKED error to the command, people don't expect a `SET` command to
get an error.

So in this commit, in these cases, we will return 0 to `CLIENT UNBLOCK`
to indicate the unblock is fail. The reason is that we assume that if a
command doesn't expect to be timedout, it also doesn't expect to be
unblocked by `CLIENT UNBLOCK`.

The old behavior of the following command will trigger panic in timeout
and get UNBLOCKED error in error. Under the new behavior, client unblock
will get the result of 0.
```
client 1> client pause 100000 write
client 2> set x x

client 1> client unblock 2 timeout
or
client 1> client unblock 2 error
```

---------

Signed-off-by: Binbin <binloveplay1314@qq.com>
Co-authored-by: Binbin <binloveplay1314@qq.com>
2025-07-24 15:20:04 +08:00
Slavomir Kaslev
7df34143c2
Prefer storing iterators on stack instead of the heap (#14200)
Refactor use of `dictGetIterator()/dictSafeGetIterator()/listGetIterator()` to
`dictInitIterator()/dictInitSafeIterator()/listRewind()` respectively which
don't allocate memory.
2025-07-24 10:17:54 +03:00
Ozan Tezcan
7ee748eda6 Retry accept() even if accepted connection reports an error (CVE-2025-48367)
In case of accept4() returns an error, we should check errno value and decide if we should retry accept4() without waiting next event loop iteration.
2025-07-24 10:06:28 +03:00
debing.sun
d7992b7f78 Fix out of bounds write in hyperloglog commands (CVE-2025-32023)
Co-authored-by: oranagra <oran@redislabs.com>
2025-07-24 10:06:28 +03:00
Lior Kogan
f6f16746e1
Update SECURITY.md and README.md (#14170)
For security vulnerability patches released under Redis Open Source 7.4
and thereafter, Redis permits users of earlier versions (7.2 and prior)
to access patches under the BSD3 license noted in REDISCONTRIBUTIONS.txt
instead of the full license requirements described in LICENSE.txt.
2025-07-22 16:48:03 +03:00
debing.sun
457089b1fe
Create global data before test instead of module load for module defrag test (#13951)
After #13816, we added defragmentation support for moduleDict, which
significantly increased global data size.
As a result, the defragmentation tests for non-global data were
affected.
Now, we move the creation of global data to before the global data test
to avoid it interfering with other tests.
Fixed the simple key test failure due to forgetting to reset stats.
2025-07-22 20:44:12 +08:00
debing.sun
45c8fcc992
Only mark the client reprocessing flag when unblocked on keys (#14165)
This PR is based on https://github.com/valkey-io/valkey/pull/2109

When we refactored the blocking framework we introduced the client
reprocessing infrastructure. In cases the client was blocked on keys, it
will attempt to reprocess the command. One challenge was to keep track
of the command timeout, since we are reprocessing and do not want to
re-register the client with a fresh timeout each time. The solution was
to consider the client reprocessing flag when the client is
blockedOnKeys:

```c
    if (!(c->flags & CLIENT_REPROCESSING_COMMAND)) {
        /* If the client is re-processing the command, we do not set the timeout
         * because we need to retain the client's original timeout. */
        c->bstate.timeout = timeout;
    }
```

However, this introduced a new issue. There are cases where the client
will consecutive blocking of different types for example:
```
CLIENT PAUSE 10000 ALL
BZPOPMAX zset 1
```
would have the client blocked on the zset endlessly if nothing will be
written to it.

**Credits to @uriyage for locating this with his fuzzer testing**

The suggested solution is to only flag the client when it is
specifically unblocked on keys.

Signed-off-by: Ran Shidlansik <ranshid@amazon.com>
Co-authored-by: Ran Shidlansik <ranshid@amazon.com>
Co-authored-by: Binbin <binloveplay1314@qq.com>
2025-07-21 20:05:47 +08:00
Stav-Levi
a4ff8d6ab6
Fix KSN for HSETEX command when FXX/FNX is used (#14150)
When HSETEX fails due to FXX/FNX, it may still expire some fields due to
lazy expiry. Though, it does not send “hexpired” notification in this
case.
2025-07-21 13:59:01 +03:00
debing.sun
1e388d8b95
Fix peak memory time test (#14201)
Since INFO command can create a large amount of memory usage, it may
further increase the peak memory.
Therefore, we should get the peak memory after deleting the large
string.
2025-07-18 18:24:28 +08:00
Salvatore Sanfilippo
b528788f65
Fix vrand ping pong (#14183)
VRANDMEMBER had a bug when exactly two elements where present in the
vector set: we selected a fixed number of random paths to take, and this
will lead always to the same element. This PR should be kindly
back-ported to Redis 8.x.
2025-07-18 18:19:14 +08:00
Ali-Akber Saifee
d86cf66101
Move WITHATTRIBS token from vlinks to vsim (#14194)
# Description
The `WITHATTRIBS` token was incorrectly documented under the `vlinks`
command in #14065
2025-07-16 20:17:53 +08:00
debing.sun
75cdc51f86
Update debian buster sources to archive.debian.org (#14197)
http://deb.debian.org/debian no longer serves Debian 10 (buster); it has
been moved to http://archive.debian.org/debian.
2025-07-15 10:34:27 +08:00
Henry
ebf19e4c92
Fix memleak issues in redis-cli (#14186) 2025-07-11 22:20:00 +08:00
show1999
b8382f0540
Fix misleading io_flags assertion comment (#14187) 2025-07-11 11:23:54 +08:00
Salvatore Sanfilippo
b5d54866ac
[Vector sets] Endianess fix and speedup of data loading (#14144)
Hello, this is a patch that improves vector sets in two ways:

1. It makes the RDB format compatible with big endian machines: yeah,
they are non existent nowadays, but still it is better to be correct.
The behavior remains unchanged in little endian systems, it only changes
what happens in big endian systems in order for it to load and emit the
exact same format produced by little endian. The implementation was
*already largely safe* but for one detail.

2. More importantly, this PR saves nodes worst link score / index in a
backward compatible way, introducing also versioning information for the
serialized node encoding, that could be useful in the future. With this
information, that in the past was not saved for a programming error
(mine), there is no longer need to compute the worst link info at
runtime when loading data. This results in a speed improvement of about
30% when loading data from disk / RESTORE. The saving performance is
unaffected.

The patch was tested with care to be sure that data produced with old
vector sets implementations are loaded without issues (that is, the
backward compatibility was hand-tested). The new code is tested by the
persistence test already in the test suite, so no new test was added.
2025-07-10 10:08:59 +08:00
Ali-Akber Saifee
92e39cac96
Fix version for vector set commands.json (#14005)
# Description 

Update `since` for all vector set commands from `1.0.0` to `8.0.0`
2025-07-08 16:32:00 +08:00
Mincho Paskalev
86c8be6368
Add new KSN types - overwritten and type_changed (#14141)
## What

Add new keyspace notification event types
- OVERWRITTEN - emitted when the value of a key is completely
overwritten
- TYPE_CHANGED - when the value of a key's type changes

Used in Pub/Sub KSN mechanism. Also added module hooks for the new
types.

## Motivation

Many commands overwrite the value of a key. F.e SET completely
overwrites the value of any key, even its type. Other commands that have
the REPLACE parameter also do so.

This commit gives more granularity over following such events.
Specific use-case at hand was module that is subscribed to string events
for the sole purpose of checking if hash keys get converted to strings
via the `SET` command. Subscribing to `type_changed` event not only
removes the need to subscribe to string events but is also more correct
as not only `SET` can change the type of a key.

## List of commands emitting the new events

* SET
* MSET
* COPY
* RESTORE
* RENAME
* BITOP

Each type with STORE operation:
* SORT
* S*STORE
* Z*STORE
* GEORADIUS
* GEOSEARCHSTORE

## Usage example

### pub-sub

Emit overwritten and type-changed events...
```
$ redis-server --notify-keyspace-events KEoc
```

Generate an overwritten event that also changes the type of a key...
```
$ redis-cli
127.0.0.1:6379> lpush l 1 2 3
(integer) 3
127.0.0.1:6379> set l x
OK
```

Subscribe to the events...
```
$ ./src/redis-cli
127.0.0.1:6379> psubscribe *
1) "psubscribe"
2) "*"
3) (integer) 1
1) "pmessage"
2) "*"
3) "__keyspace@0__:l"
4) "overwritten"
1) "pmessage"
2) "*"
3) "__keyevent@0__:overwritten"
4) "l"
1) "pmessage"
2) "*"
3) "__keyspace@0__:l"
4) "type_changed"
1) "pmessage"
2) "*"
3) "__keyevent@0__:type_changed"
4) "l"
```

### Modules

As with any other KSN type subscribe to the appropriate events
```
RedisModule_SubscribeToKeyspaceEvents(
      ctx,
      REDISMODULE_NOTIFY_OVERWRITTEN | REDISMODULE_NOTIFY_TYPE_CHANGED | ...
      notificationCallback
);
```

## Implementation notes

Most of the cases are handled in `setKeyByLink` but for some commands
overwriting had to be manually checked - specifically `RESTORE`, `COPY`
and `RENAME` manually call `dbAddInternal`
2025-07-07 13:29:14 +03:00
debing.sun
4322cebc17
Ensure empty error tables in scripts don't crash (#14163)
This PR is based on: https://github.com/valkey-io/valkey/pull/2229

When calling the command `EVAL error{} 0`, Redis crashes with the
following stack trace. This patch ensures we never leave the
`err_info.msg` field null when we fail to extract a proper error
message.

---------

Signed-off-by: Fusl <fusl@meo.ws>
Signed-off-by: Binbin <binloveplay1314@qq.com>
Co-authored-by: Fusl <fusl@meo.ws>
Co-authored-by: Binbin <binloveplay1314@qq.com>
2025-07-07 10:12:51 +08:00
adamiBs
9ff8ade64a
Fix incorrect Rust 1.88.0 SHA256 checksums in modules/Makefile (#14176)
The SHA256 checksums for Rust 1.88.0 were incorrect, causing checksum
verification failures during installation. Updated with the correct
official checksums from https://static.rust-lang.org/dist/:

- x86_64-unknown-linux-gnu:
7b5437c1d18a174faae253a18eac22c32288dccfc09ff78d5ee99b7467e21bca
- x86_64-unknown-linux-musl:
200bcf3b5d574caededba78c9ea9d27e7afc5c6df4154ed0551879859be328e1
- aarch64-unknown-linux-gnu:
d5decc46123eb888f809f2ee3b118d13586a37ffad38afaefe56aa7139481d34
- aarch64-unknown-linux-musl:
f8b3a158f9e5e8cc82e4d92500dd2738ac7d8b5e66e0f18330408856235dec35
2025-07-06 22:04:50 +03:00
Jonas Kruckenberg
17ffb1ab80
chore: Rust version bump to 1.88 (#14167)
Simple version bump from Rust 1.87 to Rust 1.88 to make nightly build
again.
2025-07-06 14:44:40 +03:00
show1999
ffd41540f0
Add boundary assert to connTypeRegister (#14153)
Add boundary assertion to prevent array overflow in `connTypeRegister`
when reaching **CONN_TYPE_MAX** limit.
2025-07-04 21:12:28 +08:00
Mincho Paskalev
eb9337abf8
Fix uninitializeed RMConfigIterator::is_glob causing MSan warnings (#14171)
Recent [PR](https://github.com/redis/redis/pull/14051) causes MSan to
fail during daily CI with uninitialized value warning.
It is not a bug per se as the uninitialized member is dependent on
another member not being NULL.
With this PR now MSan does not complain.
2025-07-04 12:26:24 +03:00
Mincho Paskalev
15706f2e82
Module set/get config API (#14051)
# Problem

Some redis modules need to call `CONFIG GET/SET` commands. Server may be
ran with `rename-command CONFIG ""`(or something similar) which leads to
the module being unable to access the config.

# Solution

Added new API functions for use by modules
```
RedisModuleConfigIterator* RedisModule_GetConfigIterator(RedisModuleCtx *ctx, const char *pattern);
void RedisModule_ReleaseConfigIterator(RedisModuleCtx *ctx, RedisModuleConfigIterator *iter);
const char *RedisModule_ConfigIteratorNext(RedisModuleConfigIterator *iter);
int RedisModule_GetConfigType(const char *name, RedisModuleConfigType *res);
int RedisModule_GetBoolConfig(RedisModuleCtx *ctx, const char *name, int *res);
int RedisModule_GetConfig(RedisModuleCtx *ctx, const char *name, RedisModuleString **res);
int RedisModule_GetEnumConfig(RedisModuleCtx *ctx, const char *name, RedisModuleString **res);
int RedisModule_GetNumericConfig(RedisModuleCtx *ctx, const char *name, long long *res);
int RedisModule_SetBoolConfig(RedisModuleCtx *ctx, const char *name, int value, RedisModuleString **err);
int RedisModule_SetConfig(RedisModuleCtx *ctx, const char *name, RedisModuleString *value, RedisModuleString **err);
int RedisModule_SetEnumConfig(RedisModuleCtx *ctx, const char *name, RedisModuleString *value, RedisModuleString **err);
int RedisModule_SetNumericConfig(RedisModuleCtx *ctx, const char *name, long long value, RedisModuleString **err);
```

## Implementation

The work is mostly done inside `config.c` as I didn't want to expose the
config dict outside of it. That means each of these module functions has
a corresponding method in `config.c` that actually does the job. F.e
`RedisModule_SetEnumConfig` calls `moduleSetEnumConfig` which is
implemented in `config.c`

## Notes

Also, refactored `configSetCommand` and `restoreBackupConfig` functions
for the following reasons:
- code and logic is now way more clear in `configSetCommand`. Only
caveat here is removal of an optimization that skipped running apply
functions that already have ran in favour of code clarity.
- Both functions needlessly separated logic for module configs and
normal configs whereas no such separation is needed. This also had the
side effect of removing some allocations.
- `restoreBackupConfig` now has clearer interface and can be reused with
ease. One of the places I reused it is for the individual
`moduleSet*Config` functions, each of which needs the restoration
functionality but for a single config only.

## Future

Additionally, a couple considerations were made for potentially
extending the API in the future
- if need be an API for atomically setting multiple config values can be
added - `RedisModule_SetConfigsTranscationStart/End` or similar that can
be put around `RedisModule_Set*Config` calls.
- if performance is an issue an API
`RedisModule_GetConfigIteratorNextWithTypehint` or similar may be added
in order not to incur the additional cost of calling
`RedisModule_GetConfigType`.

---------

Co-authored-by: Oran Agra <oran@redislabs.com>
2025-07-03 13:46:33 +03:00
debing.sun
5b7eec4c81
Fix crash due to incorrect event deletion of evport (#14162)
This PR fixes
https://github.com/redis/redis/issues/14056#issuecomment-3026114590

## Summary
Because evport uses `eventLoop->events[fd].mask` to determine whether to
remove the event, but in ae.c we call `aeApiDelEvent()` before updating
`eventLoop->events[fd].mask`, this causes evport to always see the old
value, and as a result, `port_dissociate()` is never called to remove
the fd.
This issue may not surface easily in a non-multithreaded, but since in
the multi-threaded case we frequently reassign fds to different threads,
it makes the crash much more likely to occur.
2025-07-03 14:41:26 +08:00
Eran Hadad
a7d91145c0
Update Bloom, TS, and JSON Modules to Version 8.1.90 (#14160) 2025-07-02 22:13:39 +03:00
alonre24
2826fc834a
Update redisearch to 8.2 RC1 (#14159)
[#Q6329](https://github.com/RediSearch/RediSearch/pull/6329),
[#Q6329](https://github.com/RediSearch/RediSearch/pull/6394) -
Introducing the new SVS-VAMANA vector index type which supports vector
compression (optimized on Intel machines)
2025-07-02 22:10:42 +03:00
Mincho Paskalev
ad8c7de3fe
Fix assertion in updateClientMemUsageAndBucket (#14152)
## Description

`updateClientMemUsageAndBucket` is called from the main thread to update
memory usage and memory bucket of a client. That's why it has assertion
that it's being called by the main thread.

But it may also be called from a thread spawned by a module.
Specifically, when a module calls `RedisModule_Call` which in turn calls
`call`->`replicationFeedMonitors`->`updateClientMemUsageAndBucket`.
This is generally safe as module calls inside a spawned thread should be
guarded by a call to `ThreadSafeContextLock`, i.e the module is holding
the GIL at this point.

This commit fixes the assertion inside `updateClientMemUsageAndBucket`
so that it encompasses that case also. Generally calls from
module-spawned threads are safe to operate on clients that are not
running on IO-threads when the module is holding the GIL.

---------

Co-authored-by: Yuan Wang <wangyuancode@163.com>
Co-authored-by: debing.sun <debing.sun@redis.com>
2025-07-02 11:55:57 +03:00
Slavomir Kaslev
0d8e750883
Add CLUSTER SLOT-STATS command (#14039)
Add CLUSTER SLOT-STATS command for key count, cpu time and network IO
per slot currently.

The command has the following syntax

    CLUSTER SLOT-STATS SLOTSRANGE start-slot end-slot

or

    CLUSTER SLOT-STATS ORDERBY metric [LIMIT limit] [ASC/DESC]

where metric can currently be one of the following

    key-count -- Number of keys in a given slot
cpu-usec -- Amount of CPU time (in microseconds) spent on a given slot
network-bytes-in -- Amount of network ingress (in bytes) received for
given slot
network-bytes-out -- Amount of network egress (in bytes) sent out for
given slot

This PR is based on:
    valkey-io/valkey#351
    valkey-io/valkey#709
    valkey-io/valkey#710
    valkey-io/valkey#720
    valkey-io/valkey#840

Co-authored-by: Kyle Kim <kimkyle@amazon.com>
Co-authored-by: Madelyn Olson <madelyneolson@gmail.com>
Co-authored-by: Harkrishn Patro <harkrisp@amazon.com>

---------

Co-authored-by: Kyle Kim <kimkyle@amazon.com>
Co-authored-by: Madelyn Olson <madelyneolson@gmail.com>
2025-07-01 20:26:51 +03:00
debing.sun
fa040a72c0
Add XDELEX and XACKDEL commands for stream (#14130)
## Summary and detailed design for new stream command

## XDELEX

### Syntax
```
XDELEX key [KEEPREF | DELREF | ACKED] IDS numids id [id ...]
```

### Description
The `XDELEX` command extends the Redis Streams `XDEL` command, offering
enhanced control over message entry deletion with respect to consumer
groups. It accepts optional `DELREF` or `ACKED` parameters to modify its
behavior:

- **KEEPREF:** Deletes the specified entries from the stream, but
preserves existing references to these entries in all consumer groups'
PEL. This behavior is similar to XDEL.
- **DELREF:** Deletes the specified entries from the stream and also
removes all references to these entries from all consumer groups'
pending entry lists, effectively cleaning up all traces of the messages.
- **ACKED:** Only trims entries that were read and acknowledged by all
consumer groups.

**Note:** The `IDS` block can appear at any position in the command,
consistent with other commands.

### Reply
Array reply, for each `id`:
- `-1`: No such `id` exists in the provided stream `key`.
- `1`: Entry was deleted from the stream.
- `2`: Entry was not deleted, but there are still dangling references.
(ACKED option)

## XACKDEL

### Syntax
```
XACKDEL key group [KEEPREF | DELREF | ACKED] IDS numids id [id ...]
```

### Description
The `XACKDEL` command combines `XACK` and `XDEL` functionalities in
Redis Streams. It acknowledges specified message IDs in the given
consumer group and attempts to delete corresponding stream entries. It
accepts optional `DELREF` or `ACKED` parameters:

- **KEEPREF:** Acknowledges the messages in the specified consumer group
and deletes the entries from the stream, but preserves existing
references to these entries in all consumer groups' PEL.
- **DELREF:** Acknowledges the messages in the specified consumer group,
deletes the entries from the stream, and also removes all references to
these entries from all consumer groups' pending entry lists, effectively
cleaning up all traces of the messages.
- **ACKED:** Acknowledges the messages in the specified consumer group
and only trims entries that were read and acknowledged by all consumer
groups.


### Reply
Array reply, for each `id`:
- `-1`: No such `id` exists in the provided stream `key`.
- `1`: Entry was acknowledged and deleted from the stream.
- `2`: Entry was acknowledged but not deleted, but there are still
dangling references. (ACKED option)

# Redis Streams Commands Extension

## XTRIM

### Syntax
```
XTRIM key <MAXLEN | MINID> [= | ~] threshold [LIMIT count] [KEEPREF | DELREF | ACKED]
```

### Description
The `XTRIM` command trims a stream by removing entries based on
specified criteria, extended to include optional `DELREF` or `ACKED`
parameters for consumer group handling:

- **KEEPREF:** Trims the stream according to the specified strategy
(MAXLEN or MINID) regardless of whether entries are referenced by any
consumer groups, but preserves existing references to these entries in
all consumer groups' PEL.
- **DELREF:** Trims the stream according to the specified strategy and
also removes all references to the trimmed entries from all consumer
groups' PEL.
- **ACKED:** Only trims entries that were read and acknowledged by all
consumer groups.

### Reply
No change.

## XADD

### Syntax
```
XADD key [NOMKSTREAM] [<MAXLEN | MINID> [= | ~] threshold [LIMIT count]] [KEEPREF | DELREF | ACKED] <* | id> field value [field value ...]
```

### Description
The `XADD` command appends a new entry to a stream and optionally trims
it in the same operation, extended to include optional `DELREF` or
`ACKED` parameters for trimming behavior:

- **KEEPREF:** When trimming, removes entries from the stream according
to the specified strategy (MAXLEN or MINID), regardless of whether they
are referenced by any consumer groups, but preserves existing references
to these entries in all consumer groups' PEL.
- **DELREF:** When trimming, removes entries from the stream according
to the specified strategy and also removes all references to these
entries from all consumer groups' PEL.
- **ACKED:** When trimming, only removes entries that were read and
acknowledged by all consumer groups. Note that if the number of
referenced entries is bigger than MAXLEN, we will still stop.

### Reply
No change.

## Key implementation

Since we currently have no simple way to track the association between
an entry and consumer groups without iterating over all groups, we
introduce two mechanisms to establish this link. This allows us to
determine whether an entry has been seen by all consumer groups, and to
identify which groups are referencing it. With this links, we can break
the association when the entry is either acknowledged or deleted.

1) Added reference tracking between stream messages and consumer groups
using `cgroups_ref`
The cgroups_ref is implemented as a rax that maps stream message IDs to
lists of consumer groups that reference those messages, and streamNACK
stores the corresponding nodes of this list, so that the corresponding
groups can be deleted during `ACK`.
In this way, we can determine whether an entry has been seen but not
ack.
2) Store a cache minimum last_id in the stream structure.
The reason for doing this is that there is a situation where an entry
has never been seen by the consume group. In this case, we think this
entry has not been consumed either. If there is an "ACKED" option, we
cannot directly delete this entry either.
When a consumer group updates its last_id, we don’t immediately update
the cached minimum last_id. Instead, we check whether the group’s
previous last_id was equal to the current minimum, or whether the new
last_id is smaller than the current minimum (when using `XGROUP SETID`).
If either is true, we mark the cached minimum last_id as invalid, and
defer the actual update until the next time it’s needed.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: moticless <moticless@github.com>
Co-authored-by: Ozan Tezcan <ozantezcan@gmail.com>
Co-authored-by: Slavomir Kaslev <slavomir.kaslev@gmail.com>
Co-authored-by: Yuan Wang <yuan.wang@redis.com>
2025-07-01 21:00:42 +08:00