mirror of
http://github.com/valkey-io/valkey
synced 2024-11-22 00:52:38 +00: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.
(cherry picked from commit aea6e71ef8
)
This commit is contained in:
parent
cde69883a1
commit
17c3ac89e7
@ -28,4 +28,5 @@ $TCLSH tests/test_helper.tcl \
|
||||
--single unit/moduleapi/keyspace_events \
|
||||
--single unit/moduleapi/blockedclient \
|
||||
--single unit/moduleapi/getkeys \
|
||||
--single unit/moduleapi/zset \
|
||||
"${@}"
|
||||
|
@ -2508,6 +2508,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;
|
||||
}
|
||||
@ -2552,6 +2553,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->zer;
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@ TEST_MODULES = \
|
||||
auth.so \
|
||||
keyspace_events.so \
|
||||
blockedclient.so \
|
||||
zset.so \
|
||||
getkeys.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