mirror of
https://codeberg.org/redict/redict.git
synced 2025-01-21 23:58:51 -05:00
RM_ZsetRem: Delete key if empty (#8453)
Without this fix, RM_ZsetRem can leave empty sorted sets which are not allowed to exist. Removing from a sorted set while iterating seems to work (while inserting causes failed assetions). RM_ZsetRangeEndReached is modified to return 1 if the key doesn't exist, to terminate iteration when the last element has been removed.
This commit is contained in:
parent
b3bdcd2278
commit
aea6e71ef8
@ -32,5 +32,6 @@ $TCLSH tests/test_helper.tcl \
|
||||
--single unit/moduleapi/getkeys \
|
||||
--single unit/moduleapi/test_lazyfree \
|
||||
--single unit/moduleapi/defrag \
|
||||
--single unit/moduleapi/zset \
|
||||
--single unit/moduleapi/stream \
|
||||
"${@}"
|
||||
|
@ -2612,6 +2612,7 @@ int RM_ZsetRem(RedisModuleKey *key, RedisModuleString *ele, int *deleted) {
|
||||
if (key->value && key->value->type != OBJ_ZSET) return REDISMODULE_ERR;
|
||||
if (key->value != NULL && zsetDel(key->value,ele->ptr)) {
|
||||
if (deleted) *deleted = 1;
|
||||
moduleDelKeyIfEmpty(key);
|
||||
} else {
|
||||
if (deleted) *deleted = 0;
|
||||
}
|
||||
@ -2657,6 +2658,7 @@ void RM_ZsetRangeStop(RedisModuleKey *key) {
|
||||
|
||||
/* Return the "End of range" flag value to signal the end of the iteration. */
|
||||
int RM_ZsetRangeEndReached(RedisModuleKey *key) {
|
||||
if (!key->value || key->value->type != OBJ_ZSET) return 1;
|
||||
return key->u.zset.er;
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,7 @@ TEST_MODULES = \
|
||||
test_lazyfree.so \
|
||||
timer.so \
|
||||
defragtest.so \
|
||||
zset.so \
|
||||
stream.so
|
||||
|
||||
|
||||
|
30
tests/modules/zset.c
Normal file
30
tests/modules/zset.c
Normal file
@ -0,0 +1,30 @@
|
||||
#include "redismodule.h"
|
||||
|
||||
/* ZSET.REM key element
|
||||
*
|
||||
* Removes an occurrence of an element from a sorted set. Replies with the
|
||||
* number of removed elements (0 or 1).
|
||||
*/
|
||||
int zset_rem(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||
if (argc != 3) return RedisModule_WrongArity(ctx);
|
||||
RedisModule_AutoMemory(ctx);
|
||||
int keymode = REDISMODULE_READ | REDISMODULE_WRITE;
|
||||
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], keymode);
|
||||
int deleted;
|
||||
if (RedisModule_ZsetRem(key, argv[2], &deleted) == REDISMODULE_OK)
|
||||
return RedisModule_ReplyWithLongLong(ctx, deleted);
|
||||
else
|
||||
return RedisModule_ReplyWithError(ctx, "ERR ZsetRem failed");
|
||||
}
|
||||
|
||||
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||
REDISMODULE_NOT_USED(argv);
|
||||
REDISMODULE_NOT_USED(argc);
|
||||
if (RedisModule_Init(ctx, "zset", 1, REDISMODULE_APIVER_1) ==
|
||||
REDISMODULE_OK &&
|
||||
RedisModule_CreateCommand(ctx, "zset.rem", zset_rem, "",
|
||||
1, 1, 1) == REDISMODULE_OK)
|
||||
return REDISMODULE_OK;
|
||||
else
|
||||
return REDISMODULE_ERR;
|
||||
}
|
16
tests/unit/moduleapi/zset.tcl
Normal file
16
tests/unit/moduleapi/zset.tcl
Normal file
@ -0,0 +1,16 @@
|
||||
set testmodule [file normalize tests/modules/zset.so]
|
||||
|
||||
start_server {tags {"modules"}} {
|
||||
r module load $testmodule
|
||||
|
||||
test {Module zset rem} {
|
||||
r del k
|
||||
r zadd k 100 hello 200 world
|
||||
assert_equal 1 [r zset.rem k hello]
|
||||
assert_equal 0 [r zset.rem k hello]
|
||||
assert_equal 1 [r exists k]
|
||||
# Check that removing the last element deletes the key
|
||||
assert_equal 1 [r zset.rem k world]
|
||||
assert_equal 0 [r exists k]
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user